LINUX.ORG.RU

Как разблокировать одновременно 2 потока?

 ,


0

3

Приветствую.

Контекст - для организации параллельной работы декодера и енкодера (онлайн трансляция) с поступающими с камеры кадрами организовал 2 потока с 2 семафорами, которые перекрестно отпускают чужой семафор и ждут на своем, но хочется еще один параллельный редко запускаемый енкодер (снимки) добавить, чтобы не декодить лишний раз.

Вопрос - как бэ из потока декодера запускать сразу 2 потока енкодеров, при этом поток декодера должен ждать завершения обоих???

В идеале бы конешно на С, т.к. сишный модуль этим занимается.

Спасибо за любые идеи )

★★★

Последнее исправление: Dimez (всего исправлений: 1)

Вопрос - как бэ из потока декодера запускать сразу 2 потока енкодеров, при этом поток декодера должен ждать завершения обоих???

декодер:

pthread_mutex_lock(&mutex);
...работаем
encode1_done = 0;
encode2_done = 0;
pthread_cond_signal(&cond_encoder1);
pthread_cond_signal(&cond_encoder2);

while (!encode1_done || !encode2_done) {
    pthread_cond_wait(&cond_decoder, &mutex);
}
pthread_mutex_unlock(&mutex);

енкодер1:

pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_encoder1, &mutex);
...работаем
encode1_done = 1;
if (encode1_done && encode2_done) {
    pthread_cond_signal(&cond_decoder);
}

pthread_mutex_unlock(&mutex);

енкодер2:

pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_encoder2, &mutex);
...работаем
encode2_done = 1;

if (encode1_done && encode2_done) {
    pthread_cond_signal(&cond_decoder);
}

pthread_mutex_unlock(&mutex);
iron ★★★★★
()
Ответ на: комментарий от iron

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

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

у меня в обоих енкодерах нет относительно друг друга критических секций

Тогда попробуй юзать одну переменную состояния для обеих потоков, а из потока декодера слать pthread_cond_broadcast().

iron ★★★★★
()
Ответ на: комментарий от wolverin

Погодите, но ведь проблема в одном и том же мутексе у обоих енкодеров!?

Верно. Но тебе обеим потокам главное выйти из режима ожидания. А кто из энкодеров захватить мютекс – пофигу. Когда они закончат работу, у выставят переменные encode0_done и encode1_done в 1 и просигналят декодеру.

Это все лишь в теории. Проверь, прокатит ли такой трюк на практике. Мне самому лень проверять, тоже сейчас сам вожусь с подобными ребусами блокировок.

iron ★★★★★
()
Последнее исправление: iron (всего исправлений: 1)
Ответ на: комментарий от wolverin

С одной стороны конечно дважды поднять семафор енкодеров не проблема, осталось понять кто последний пришел к финишу и может поднять семафор декодера…

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

мне надо именно запараллелить

Так идея в том, чтоб начать работу параллельно в обеих енкодерах сразу после pthread_cond_wait(). Т.е. ты будишь оба потока одновременно через бродкаст и они работают.

iron ★★★★★
()
Последнее исправление: iron (всего исправлений: 1)
Ответ на: комментарий от wolverin

первый вышедший из условной переменной захватит мутекс

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

iron ★★★★★
()
Последнее исправление: iron (всего исправлений: 1)
Ответ на: комментарий от wolverin

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

Да, в случае pthread_cond_signal(). В случае с pthread_cond_broadcast() – просыпаются оба.

DESCRIPTION
     The pthread_cond_broadcast() function unblocks all threads waiting for
     the condition variable cond.
iron ★★★★★
()
Последнее исправление: iron (всего исправлений: 1)
Ответ на: комментарий от iron

Поскольку pthread_cond_broadcast() заставляет все потоки, блокированные некоторым состоянием, бороться за мьютекс, ее нужно использовать аккуратно

https://www.opennet.ru/docs/RUS/ipcbook/node75.html

wolverin ★★★
() автор топика
Ответ на: комментарий от iron

Ещё раз как я понимаю условную переменную

  • блокируешь мутекс
  • встаёшь на переменную, отпуская мутекс
  • приходит событие на переменную, происходит захват мутекса
wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

приходит событие на переменную, происходит захват мутекса

Правильно… А после этого ты можешь отпустить мютекс и просигналить второму потоку чтоб он начал работу.

iron ★★★★★
()

параллельный редко запускаемый енкодер (снимки) добавить

Можно сделать разблокировку сообщениями. Например, через pipe. И уже в сообщении указывать действие - только поток или поток+снимок.

u5er
()
FUTEX_WAKE (since Linux 2.6.0)
              This operation wakes at most val of the waiters that are
              waiting (e.g., inside FUTEX_WAIT) on the futex word at the
              address uaddr.  Most commonly, val is specified as either
              1 (wake up a single waiter) or INT_MAX (wake up all
              waiters).  No guarantee is provided about which waiters
              are awoken (e.g., a waiter with a higher scheduling
              priority is not guaranteed to be awoken in preference to a
              waiter with a lower priority).


Тут пример есть:
https://habibutsu.github.io/synchronize.html

Интересно, конечно, есть ли какие-то альтернативы в pthread. Но всё что я видел помимо фьютекса пробуждает потоки по одному

P.S
Возможно, это оно:
https://stackoverflow.com/questions/40126442/best-way-to-wakeup-multiple-thre...

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 3)
Ответ на: комментарий от wolverin

Чо вы в мутексы эти вцепились. Мутекс — это для взаимных блокировок при конкуренции за ресурс. Еси тебе нужен семафор, чтоб сигналить, так и используй семафор.

slackwarrior ★★★★★
()
Ответ на: комментарий от slackwarrior

это то да, сейчас так и сделано для 2х потоков (декодер+енкодер), но в конце цикла нужно из енкодера пнуть декодер, а если ИНОГДА 2 енкодера, то и появляется дилемма кто из 2х енкодеров может переключить декодер на другой буфер и отправить его писать в него.

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

зы. а еще самый первый енкодер хоть и нагружает систему большего всего, но он нужен условно 1 раз в час (а может и сутки не нужен) в течении 1-2 минут, а второй енкодер (снимки) железно каждые 10 минут нужен

зы1. можно конечно плюнуть раз вероятность не большая встречи 2х енкодеров и делать одно за другим, но уж очень хочется не уменьшать фпс хоть и в редкие, но очень важные 1-2 минуты

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 3)
Ответ на: комментарий от wolverin

хотя… если из декодера либо пинать 2 раза семафор енкодера, либо 1 раз и 1 раз барьер - теоретически должно получиться… или нет )

или просто у енкодера сделать 2 семафора - начала и конца и из декодера пинать либо 2 раза семафор старта, либо 1 раз старт и 1 раз конца… не, тоже не то.

… а может вообще 4 поток сделать, который и будет управлять запусками и контролировать остановки потоков на основе семафоров

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 4)
Ответ на: комментарий от kvpfs_2

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

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)