Вы должны были бы уточнить, чего именно вы хотите достичь. На данный момент производители увеличивают только целое число, а потребитель уменьшает значение. Это не очень полезное занятие;) Я понимаю, что это всего лишь тестовое приложение, но все еще не ясно, какова цель этой обработки, каковы ограничения и т. Д.
Производители производят несколько «предметов». Результат этого производства представлен в виде целочисленного значения. 0 означает отсутствие элементов, 1 означает, что есть ожидающий элемент, который может принять потребитель. Это правильно? Теперь, возможно ли, чтобы производитель произвел несколько элементов до того, как какой-либо из них будет израсходован (увеличивая ячейку массива до значения выше 1)? Или он должен ждать, пока последний предмет будет израсходован, прежде чем следующий будет помещен в хранилище? Хранение ограничено или неограничено? Если оно ограничено, то распространяется ли ограничение на всех производителей или определено для каждого производителя?
То, что я ожидал, было то, что, когда производитель обновляет свои данные,
Потребитель немедленно обрабатывает его, то есть после каждого Производителя.
сообщение должно быть напечатано сообщение потребителя.
Хотя не совсем понятно, чего вы хотите достичь, я придерживаюсь этой цитаты и предполагаю следующее: существует ограничение в 1 элемент на производителя, и производитель должен ждать, пока потребитель опустошит хранилище, прежде чем новый элемент может быть помещен в ячейку, т.е. единственные допустимые значения в массиве g_lDataArray - 0 и 1.
Чтобы обеспечить максимальный параллелизм между потоками, вам понадобится пара условных переменных / мьютексов для каждой ячейки g_lDataArray (для каждого производителя). Вам также понадобится очередь обновлений, представляющая собой список производителей, которые представили свои работы, и пара условных переменных / мьютексов для ее защиты. Это заменит g_lChangedProducerId, который может содержать только одно значение за раз.
Каждый раз, когда производитель хочет поместить элемент в хранилище, он должен получить соответствующую блокировку, проверить, не является ли хранилище пустым (g_lDataArray [lProducerId] == 0), если не ожидать переменную условия, а затем увеличить значение. ячейка, снять удерживаемую блокировку, получить блокировку потребителя, добавить его идентификатор в очередь обновлений, уведомить потребителя, снять блокировку потребителя. Конечно, если производитель выполнит какие-либо реальные вычисления, производящие некоторый реальный элемент, эта работа должна быть выполнена вне области какой-либо блокировки перед попыткой поместить элемент в хранилище.
В псевдокоде это выглядит так:
// do some computations
item = compute();
lock (mutexes[producerId]) {
while (storage[producerId] != 0)
wait(condVars[producerId]);
storage[producerId] = item;
}
lock (consumerMutex) {
queue.push(producerId);
signal(consumerCondVar);
}
Потребитель должен действовать следующим образом: получить свою блокировку, проверить, есть ли какие-либо ожидающие обновления для обработки, если не ожидать переменную условия, вынуть одно обновление из очереди (то есть номер производителя обновлений), получить блокировку для производителя, который будет обрабатывать обновление, уменьшить ячейку, уведомить производителя, снять блокировку производителя, снять его блокировку и, наконец, обработать обновление.
lock (consumerMutex) {
while (queue.isEmpty())
wait(consumerCondVar);
producerId = queue.pop();
lock (mutexex[producerId]) {
item = storage[producerId];
storage[producerId] = 0;
signal(condVars[producerId]);
}
}
//process the update
process(item);
Надеюсь, вам нужен этот ответ.