posix pipe в качестве рабочей очереди - PullRequest
5 голосов
/ 28 марта 2012

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

Потребитель:

A) Acquires Lock
B) While Queue empty
      Wait on Condition Variable (thus suspending thread and releasing lock)
C) Work object retrieved from queue
D) Lock is released
E) Do Work
F) GOTO A

Производитель:

A) Acquires Lock
B) Work is added to queue
C) condition variable is signaled (potentially releasing worker)
D) Lock is released

Я просматривал некоторый код и увидел реализацию, использующую каналы POSIX (раньше я не видел эту технику).

Потребитель:

A) Do select on pipe (thus suspending thread while no work)
B) Get Job from pipe
C) Do Work
D) GOTO A

Производитель:

A) Write Job to pipe.

Поскольку производитель и потребитель являются потоками внутри одного и того же приложения (таким образом, они совместно используют одно и то же адресное пространство и, следовательно, указатели между ними являются действительными); задания записываются в канал как адрес рабочего объекта (объект C ++). Поэтому все, что нужно записать / прочитать из канала, это 8-байтовый адрес.

Мой вопрос:

  • Является ли это обычной техникой (защищен ли я от этого) и каковы преимущества / недостатки?

Мое любопытство было задето, потому что техника трубы не включает никаких видимых блокировок или сигналов (они могут быть скрыты в избранном). Поэтому мне было интересно, будет ли это более эффективным?

Edit:

Основано на комментариях в ответе Максима Егорушкина.

На самом деле «продюсер» в этом сценарии участвует в большом количестве операций ввода-вывода из большого количества параллельных источников. Поэтому я подозреваю, что первоначальный автор очень хотел, чтобы этот поток не блокировал ни при каких обстоятельствах, но также не хотел высокой стоимости работы в потоке «Производитель».

Ответы [ 4 ]

4 голосов
/ 28 марта 2012

Как уже упоминалось, люди используют каналы в качестве очередей, чтобы избежать блокировки переменной условия в неблокирующем потоке ввода-вывода (т. Е. В потоке, который обрабатывает несколько сокетов и блоков в select / epoll). , Если поток ввода-вывода блокирует переменную условия или мьютекс, он больше не может делать неблокирующий ввод-вывод.

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

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

1 голос
/ 28 марта 2012

Я сделал это.Это старая школа, но она работает.

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

0 голосов
/ 28 марта 2012

Это из-за выбора и его структуры.Как вы можете видеть на странице руководства

select () и pselect () позволяют программе отслеживать несколько файловых дескрипторов, ожидая, пока один или несколько файловых дескрипторов станут «готовыми» для некоторого классаОперация ввода / вывода (например, возможен ввод).Файловый дескриптор считается готовым, если возможно выполнить соответствующую операцию ввода-вывода (например, read (2)) без блокировки.

Ключ в приведенном выше - «ожидание до одного илибольше FD становятся готовыми ».Это точка синхронизации между двумя потоками.

0 голосов
/ 28 марта 2012

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

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

РЕДАКТИРОВАТЬ: Я думаю, что я мог бы также сделать стандартную рекомендацию, так как никто не пришел с какими-либо явно авторитетными комментариями.

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

...