Сколько мьютекса и переменной cond? - PullRequest
0 голосов
/ 16 июня 2011

Я работаю в пуле потоков, и будет пять отдельных потоков и одна очередь.Все пять потоков конкурируют, чтобы получить работу из очереди, и я знаю основную идею, что мне нужно сделать блокировку / разблокировку и ожидание / сигнал.

Но я не уверен, сколько мьютекса и переменной cond ядолжен иметь.Сейчас у меня есть только одна переменная mutex и cond, и все пять потоков будут использовать ее.

Ответы [ 3 ]

3 голосов
/ 16 июня 2011

Один мьютекс и по крайней мере одна условная переменная.

Один мьютекс, потому что есть одна «вещь» (то есть фрагмент памяти) для синхронизации доступа: общее состояние между всеми работниками и потоком, выполняющим работу..

Одна условная переменная для каждого условия, для которого один или несколько потоков должны ожидать.По крайней мере, вам нужна одна условная переменная для ожидания новых заданий, условие здесь следующее: «Есть ли еще что-то, что нужно сделать?»(или наоборот: «рабочая очередь пуста?»).


Несколько более существенным ответом будет то, что существует взаимно-однозначное отношение между мьютексом и соответствующими переменными условия, иотношения один-к-одному между общими состояниями и мьютексами.Исходя из того, что вы нам рассказали, и поскольку вы учитесь, я рекомендую использовать только одно общее состояние для вашего дизайна.Когда или если вам нужно более одного состояния, я бы порекомендовал поискать некоторые концепции более высокого уровня (например, каналы, фьючерсы / обещания) для построения на абстракции.

В любом случае, не используйте одно и то же условиепеременная с разными мьютексами.

2 голосов
/ 16 июня 2011

Разрабатывать @ решение Ивана ...

Вместо условной переменной mutex + вы можете использовать счетный семафор + атомарные операции для создания очень эффективной очереди.

semaphore dequeue_sem = 0;
semaphore enqueue_sem = 37; // or however large you want to bound your queue

Операция постановки в очередь просто:

wait_for(enqueue_sem)
atomic_add_to_queue(element)
signal(dequeue_sem)

Операция удаления из очереди:

wait_for(dequeue_sem)
element = atomic_remove_from_queue()
signal(enqueue_sem)

"atomic_add_to_queue" и "atomic_remove_from_queue" обычно реализуются с использованием атомарного сравнения и обмена в тесном цикле.

Помимо своей симметрии, эта формулировка ограничивает максимальный размер очереди; если поток вызывает enqueue () для полной очереди, он блокируется. Это почти наверняка то, что вы хотите для любой очереди в многопоточной среде. (Ваш компьютер имеет ограниченную память; по возможности следует избегать его использования без ограничений.)

Если вы используете мьютекс и условные переменные, вам нужно два условия: одно для очереди, чтобы ждать (и deque для подачи сигнала), и другое для обратного. Условия означают «очередь не заполнена» и «очередь не пуста», соответственно, и код очереди / очереди аналогично симметричен.

1 голос
/ 16 июня 2011

Я думаю, что вы могли бы выполнить кражу работы из очереди, не блокируя ее вообще посредством операций с блокировкой, если вы организовали ее как стек / связанный список (для предотвращения проблемы, описанной в комментариях к этому ответу, потребуется семафор вместо переменной условия). 1001 *

Псевдокод выглядит так:

  1. кандидат = руководитель.
  2. если (кандидат == ноль) wait_for_semaphore;
  3. if (кандидат == InterlockedCompareExchange (руководитель, кандидат-> следующий, кандидат)) execute_work (кандидат-> данные);
  4. еще перейти к 1;

Конечно, добавление работы в очередь также должно осуществляться через InterlockedCompareExchange и в этом случае сигнализировать семафор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...