Потокобезопасность для очереди STL - PullRequest
19 голосов
/ 27 октября 2010

Я использую очередь для связи между потоками. У меня есть один читатель и несколько писатель темы. У меня вопрос: нужно ли блокировать очередь каждый раз, когда я использую push / front / pop из очереди для читателя? Могу ли я сделать что-то вроде следующего:

//reader threads
getLock();
get the number of elements from the queue
releaseLock();

int i = 0;
while( i < numOfElements){
    queue.front();
    queue.pop();
    i++
}

Идея состоит в том, что я хочу уменьшить степень детализации заблокированного кода, и поскольку поток записи будет выполнять запись только в конец очереди, и существует только один поток чтения. Пока я получу количество элементов, тогда я смогу получить элементы из очереди ИЛИ мне нужно также заключить в замок front() и pop()?

Ответы [ 5 ]

10 голосов
/ 27 октября 2010

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

Каждый писатель будет:

  • Приобрести замок
  • Вставить элемент (ы) в очередь, на которую в данный момент указывает указатель очереди
  • Снять блокировку

Читатель может затем сделать следующее:

  • Получить блокировку
  • Переключить указатель очереди, чтобы он указывал на вторую очередь
  • Снять блокировку
  • Обработка элементов из первой очереди
9 голосов
/ 27 октября 2010

Любой тип, который явно не заявляет свои гарантии безопасности потока, всегда должен контролироваться мьютексом.Тем не менее, stdlib вашей реализации может допускать некоторые варианты этого - но вы не можете знать для всех реализаций std :: queue.

Поскольку std :: queue оборачивает другой контейнер (это адаптер контейнера), вынужно взглянуть на базовый контейнер, который по умолчанию является deque.

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

Я недостаточно изучил C ++ 0x, чтобы узнать, есть ли у него какое-либо решение для этого из коробки., но это может быть другой вариант.

2 голосов
/ 27 октября 2010

Это абсолютно зависит от реализации. Стандарт C ++ не упоминает ни о потоках, ни о безопасности потоков, поэтому то, будет ли это работать, зависит от того, как ваша реализация обрабатывает элементы очереди.

В вашем случае читатель фактически выталкивает очередь, что считается операцией записи. Я сомневаюсь, что какая-либо из распространенных реализаций фактически гарантирует безопасность потоков в этом случае, когда несколько потоков одновременно записывают в контейнер. По крайней мере, VC ++ не:

Для чтения в тот же объект, объект является потокобезопасным для чтения, когда нет записывающих в других потоках.

Для записи в один и тот же объект объект является поточно-ориентированным для записи из одного потока, когда нет читателей в других потоках.

1 голос
/ 24 октября 2012

Ваша догадка верна: даже если вы не можете рассчитывать на то, что очередь STD является поточно-ориентированной, очередь должна быть поточно-безопасной по схеме .

Хорошее объяснение того, почему это так, и стандартная реализация потоковобезопасных, свободных от блокировки очередей в C ++ дана van Dooren

1 голос
/ 28 октября 2010

Иногда вы можете решить много проблем, связанных с параллелизмом, избегая совместного использования состояния или ресурсов между потоками. Если у вас есть несколько потоков, которые одновременно обращаются к контейнеру, чтобы продвинуть свою работу, попробуйте заставить их работать с выделенными контейнерами. В определенных точках вы затем собираете элементы контейнеров в центральный контейнер не одновременно.

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

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