Подтвердить что ты не робот

Защита потоков для очереди STL

Я использую очередь для связи между потоками. У меня есть один читатель и несколько потоков сообщений. Мой вопрос: мне нужно блокировать очередь каждый раз, когда я использую 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() в блокировку?

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

  • Приобретение блокировки
  • Нажмите элемент в очередь, на которую указывает указатель очереди
  • Блокировка блокировки

Затем читатель может сделать следующее:

  • Приобретение блокировки
  • Указатель очереди очереди, чтобы указать на вторую очередь
  • Блокировка блокировки
  • Элементы процесса из первой очереди

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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