Как я могу построить незанятую очередь?
Я провел сегодня, глядя в беззаботные очереди. У меня многократная продюсерская ситуация с несколькими потребителями. Я применил для тестирования систему, использующую функцию блокировки SList под Win32, и она удвоила производительность моего сильно зависящего от потока кода на основе задач. К сожалению, я хочу поддерживать несколько платформ. Блокировка на нескольких платформах сама по себе не проблема, и я могу с уверенностью предположить, что я могу блокировать без проблем. Однако фактическая реализация меня теряет.
Большая проблема заключается в том, что вам нужно гарантировать, что список push/pop будет использовать только один вызов с блокировкой. В противном случае вы оставляете место для другого потока, чтобы зажать и повредить вещи. Я не уверен, как реализация microsoft работает под капотом и хотела бы узнать больше.
Может ли кто-нибудь указать мне на полезную информацию (платформа и язык довольно неуместны)?
Добавленный к тому, что я хотел бы знать, можно ли его реализовать беззаботный вектор. У меня было бы огромное количество пользы:)
Ура!
Изменить: прочитав статью о траве DDJ, я вижу уменьшенную очередь блокировки, которая очень похожа на ту, что у меня уже была. Однако я замечаю, что в конце есть документы, которые могут выполнять истинную блокировку очереди с использованием двойной операции сравнения и свопинга (DCAS). Кто-нибудь выполнил очередь, используя cmpxchg8b (или cmpxchg16b, если на то пошло)?
Я просто размышляю над этим вопросом (не прочитав документы), но вы можете использовать эту систему для одновременного обновления указателя головы и хвоста и, таким образом, избегать проблем с другим потоком, прыгающим между двумя атомными операциями. Однако вам все равно нужно получить следующий указатель главы, чтобы проверить, что против указателя хвоста, чтобы увидеть, только что изменили хвост. Как вы избегаете другого потока, изменяющего эту информацию, в то время как другой поток готовится сделать это сам? Как именно это реализовано беззаконным способом? Или мне лучше читать небезопасность, которая является исследовательской статьей?;)
Ответы
Ответ 1
Вероятно, вы могли бы реализовать ограниченную очередь с наименьшими трудностями... Я думал об этом в последнее время и придумал этот дизайн, но вы, вероятно, найдете много других интересных идей: (ПРЕДУПРЕЖДЕНИЕ: у него могут быть некоторые проблемы! )
- очередь представляет собой массив указателей на элементы
- вам нужно управлять двумя указателями (head, tail), которые работают над очередью так же, как круговой буфер
- if
head
== tail
нет элементов
- если вы хотите
enqueue(ptr)
, Interlocked-Swap tail
с NULL (prev_tail
- это измененное значение)
- if
prev_tail == NULL
, повторите попытку
- if
prev_tail + 1
(с wraparound) == head
, ваша очередь заполнена
- иначе поставьте
ptr
в *prev_tail
и назначьте prev_tail+1
в tail
(следите за оберткой буфера)
- для
dequeue()
сделать копию tmp_head = head и проверить tmp_head == tail
- если оно истинно, верните, потому что очередь пуста
- если он ложный
- сохранить
*tmp_head
как ptr
- выполните CAS: сравните
head
с tmp_head
swap head
с помощью head+1
- если CAS не удалось - запустите всю функцию через
- если это удалось - return
ptr
Вы можете подождать как на CAS, так и на голове, но если очередь не будет решена, вы должны преуспеть в первый раз без лишних блокировок.
Неограниченные очереди "бит" сложнее;) Но для большинства потребностей вы должны создать достаточно большую очередь.
Ответ 2
Я думаю, здесь есть интересная дискуссия по этому вопросу здесь, в частности этот поток.
Ответ 3
Возможно, вы захотите взглянуть на реализацию Травы Саттерса в очереди с низкой блокировкой.
http://www.drdobbs.com/hpc-high-performance-computing/211601363
Он использует атомику С++ 0x, но ее было бы (должно быть) легко реализовать с вашими конкретными архитектурами атомными операциями (__sync_ * с использованием GNU, atomic_ * на Solaris и т.д.).
Ответ 4
Эти ребята, может быть, вы можете найти там какое-то вдохновение. Другими интересными файлами являются yqueue.hpp и atomic_ptr.hpp
Ответ 5
Решение viraptor является блокировкой, не существует множественной произвольной очереди/множественной потребительской очереди algotihms.