параллельная очередь в C ++ - PullRequest
2 голосов
/ 19 сентября 2010

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

Проблема с чтением.Если в очереди нет данных, я бы хотел, чтобы мой поток ждал, пока данные не станут доступны.Один очевидный способ сделать это - получить мьютекс чтения и продолжать опрашивать очередь каждые N тактов, но это, очевидно, не лучший подход.Что подводит меня к условным переменным.Есть ли у кого-нибудь хороший ресурс, который обсуждает реализацию блокировки очереди в C ++ с условными переменными (предпочтительно на основе pthreads)?

В частности, я вижу следующие проблемы:

  1. Как только запись сделанапоток записи будет делать pthread_cond_signal, что данные существуют, но как он узнает, что какой-то поток чтения ожидает?Недопустимо вызывать pthread_cond_signal, если не существует pthread_cond_wait.
  2. Можно ли вызывать pthread_cond_broadcast вместо pthread_cond_signal?Возможно, это может обойти проблему с pthread_cond_wait.Кроме того, это кажется более логичным, так как несколько потоков считывателя, безусловно, являются реальной возможностью.
  3. Также представляется, что потоки считывателя и записывающего устройства должны быть заблокированы одним и тем же мьютексом, чтобы использовать переменную условия.Если это правда, тогда у нас серьезная проблема.

Ответы [ 5 ]

3 голосов
/ 19 сентября 2010

У меня есть реализация, использующая тот же мьютекс из http://danborn.net/code/, но, как я упоминал ранее, поскольку в нем используется переменная условия, он также использует 1 мьютекс.

А вот и буст-версия, опять же с одним мьютексом: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

2 голосов
/ 19 сентября 2010

Пример 12-3 из этого блога C ++ о многопоточности должен дать вам эталонную реализацию, но я думаю, что вы опасно близки к успеху сами по себе. Решение ваших конкретных проблем:

  1. не запрещено сигнализировать, когда нет официантов. Это абсолютно законно, и вы можете использовать этот факт. (Где ты это прочитал, кстати?)
  2. pthread_cond_broadcast вызывает одну большую проблему: стадо слонов , где все потоки n пробуждаются и начинают вытягивать память между кешами, даже если только один из них может сделать пересылку прогресс. Это будет работать, но не так эффективно.
  3. Вы можете передавать сигналы из любого места, даже из потока, который никогда не должен иметь дело с мьютексом, о котором идет речь. Ваши pthread_cond_wait вызовы должны освободить мьютекс чтения; это единственное требование, и это единственный мьютекс, который когда-либо должен взаимодействовать с условной переменной.

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

2 голосов
/ 19 сентября 2010

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

Кроме того, в контексте многопоточного программирования, вызывая что-то как операцию чтения обычно подразумевает, что это не меняет состояние общего ресурса. Если под "читать" Вы действительно имеете в виду «удалить элемент из головы очереди», который меняет состояние очередь (другими словами, это также «запись».) Для вашей ситуации может быть лучше думать с точки зрения «потребителя и производителя», а не «читателя и писателя».

Для вашей ситуации должно быть достаточно одного мьютекса (чтобы гарантировать исключительный доступ к очереди) и двух условных переменных («данные доступны», «доступно свободное пространство»). (Если очередь может расти динамически, вам не понадобится условная переменная «доступно свободное место»; Я просто упоминаю это для полноты.)

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

1 голос
/ 19 сентября 2010

Рассматривали ли вы использование семафора вместо условной переменной? Семафор является ожидаемым и может представлять состояние «очередь не пуста», даже когда нет ожидающих потоков.

0 голосов
/ 19 сентября 2010

Простой пример повышения :: условие находится здесь .

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