LINUX.ORG.RU

Семафоры и дохнущий процесс

 ,


2

5

Сап. Есть линукс. Есть два демона. Один (сервер) генерирует поток картинок (видео) в виде кучи raw-данных и кладет их в shared memory. Второй демон (клиент) читает эти картинки и что-то с ними делает. Проблема стара, как мир: нужно сделать синхронизацию, чтобы клиент не читал неконсистентные данные, пока сервер их обновляет.

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

Код тут.

Вопрос: как организовать межпроцессную блокировку так, чтобы она снималась, если процесс сдох?

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

Другое решение - использовать SysV-семафоры, у которых есть SEM_UNDO. Не нравится требованием иметь какой-то файл на файловой системе. И вообще, нет ли подводных камней с SEM_UNDO?

Альтернатива - flock на файл. Не подходит отсутствием таймаута (клиенту важно).

Пните в нужном направлении пжалста. Можно только линукс-решение, переносимость на бсд* и прочее не интересует.

★★★★

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

shared memory

Нафига? Чем unix сокеты не устроили?

Альтернатива - flock на файл. Не подходит отсутствием таймаута (клиенту важно).

alarm + EINTR

cloun1901
()

Сделай две очереди (ring), в одну очередь сервер кладёт номера буферов, которые можно обрабатывать, в другую - клиент уже обработанных буферов, из которой сервер потом может их брать и переиспользовать. Ищи lockless ringbuffer, их полно. Можно из DPDK выдрать, чтобы всё не тащить.

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

Нафига? Чем unix сокеты не устроили?

Один фрейм весит 8мб. Фреймов может быть в районе 30 в секунду.

alarm + EINTR

Как костыль сойдет, но хотелось бы чего-то менее уродского.

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

Норм решение. Оставлю на случай, если чего-то менее простого не найдется.

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

Один фрейм весит 8мб. Фреймов может быть в районе 30 в секунду.

Передавай ссылку на буфер в shm через сокет. Короче, передача сообщений вместо блокировок.

cloun1901
()
Ответ на: комментарий от byko3y

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

liksys ★★★★
() автор топика

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

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

anonymous
()
Ответ на: комментарий от liksys

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

Это POSIX,1-2008:

https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/idx/ip.html

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

Шаренная память это не для всех. Это очень низкоуровневая штука. Плюсую кольцевые буфера или юникс-сокеты

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

Обработка ошибок написана хорошо. Просто мир несовершенен и произойти может все что угодно. Поэтому всякого рода обработчики сигналов для освобождения семафоров идут лесом. Прилетит SIGKILL - и труба.

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

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

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

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

Вот именно поэтому я и хочу это использовать, чтобы целевая платформа (арм) не загнулась от межпроцессного жонглирования данными.

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

Шаренная память это не для всех. Это очень низкоуровневая штука. Плюсую кольцевые буфера или юникс-сокеты

Разделяемая память не более низкоуровнева, чем сокеты. Проблема не в низкоуровневости, а в недоработанности посиксового IPC.

byko3y ★★★★
()

2all: всем спасибо за советы. Решение с кольцевыми буферами и сокетами для контроля выглядит нормальным, но слишком громоздким как по мне. Если других вариантов не найдется, то буду делать что-нибудь из этого. Может быть существует какой-нибудь уродский linux-only хак? С фьютексами там, хз.

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

Тут нет моей или твоей логики, есть логика высвобождать ресурсы перед смертью, неважно от каких причин эта смерть наступает. А если ты не можешь этого сделать корректно, о чём вообще тогда может идти речь?

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

Ты в принципе не можешь корректно «освободить» взятый семафор, потому что циферка в семафоре по какому-то идиотизму не считается ресурсом.

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

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

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

логика высвобождать ресурсы перед смертью, неважно от каких причин эта смерть наступает. А если ты не можешь этого сделать корректно, о чём вообще тогда может идти речь?

Ты предлагаешь писать свою ОС, которая высвободит свои ресурсы?

byko3y ★★★★
()

flock на файл. Не подходит отсутствием таймаута

У flock() есть флаг LOCK_NB, который делает его неблокирующим.

i-rinat ★★★★★
()
Ответ на: комментарий от liksys

несколько сырых fhd@50 uyvy 1.5gbit/s вполне через loopback по сокетам проливается и не особо нагружает x86 железку

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

Я же написал, что это арм. Копирование данных в шаред-мемори занимает 10ms. По сокету будет быстрее? Думаю, нет.

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

Для кольцевого буфера и случая «один производитель - один потребитель» даже синхронизация на x86 не нужна, на ARM барьеров будет достаточно.

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

Без понятия.

Хотя погоди. Разве sem_open возвращает файловый дескриптор? Там же указатель на структуру, внутренний формат которой не специфицирован.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от liksys

В линуксе, вроде бы, нет системного вызова для реализации shm_open(), так что там создаётся файл в /dev/shm. Хоть он и не на диске, это файл, поэтому flock() должен работать.

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

Надо поэкспериментировать. Там даже ftruncate работает, так что должно, наверное.

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

Странный вывод, но могу и относительно него ответить. Я предлагаю писать код так, чтобы не пришлось писать свою ОС.

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

Как ты предлагаешь решать проблему принципиальной невозможности освобождения семафора?

- Надо освобождать ресурсы!
- Как?
- Не знаю, как, но надо! Пишите код правильно!
- Как писать-то?
- Правильно! Чо непонятного-то?
liksys ★★★★
() автор топика
Последнее исправление: liksys (всего исправлений: 2)
Ответ на: комментарий от anonymous

Странный вывод, но могу и относительно него ответить. Я предлагаю писать код так, чтобы не пришлось писать свою ОС

Да, потому я пишу под винду.

byko3y ★★★★
()

Вопрос: как организовать межпроцессную блокировку так, чтобы она снималась, если процесс сдох?

Поддерживаю довод грамотного форумчанина о том, что правильным решением будет убирать за собой при внезапном завершении работы процесса.

Каким образом это осуществить? Я бы сначала создал главный процесс-смотритель, а из него уже порождал процессы-потомки: «писателя» и «читателя». В случае отказа в работе одного либо обоих потомков «родитель» прибирает за «детишками» и перезапускает их. Так программа будет работать гораздо надёжнее.

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

Опции сделать смотрителя нет. Это нормальное требование, когда процессы спаунятся независимо. Просто в посиксе семафоры кто-то сделал через жопу и про SEM_UNDO забыли

liksys ★★★★
() автор топика

Решение для будущих поколений:

На линуксе можно сделать flock() на дескриптор, открытый shm_open().

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

какого хрена этого нет в посиксе?

Возможно, что объяснение в секции BUGS в man semop:

When a process terminates, its set of associated semadj structures
is used to undo the effect of all of the semaphore operations it
performed with the SEM_UNDO flag. This raises a difficulty: if one (or
more) of these semaphore adjustments would result in an attempt to
decrease a semaphore's value below zero, what should an implementation
do? One possible approach would be to block until all the semaphore
adjustments could be performed. This is however undesirable since it
could force process termination to block for arbitrarily long periods.
Another possibility is that such semaphore adjustments could be ignored
altogether (somewhat analogously to failing when IPC_NOWAIT is specified
for a semaphore operation). Linux adopts a third approach: decreasing the
semaphore value as far as possible (i.e., to zero) and allowing process
termination to proceed immediately.
xaizek ★★★★★
()
Ответ на: комментарий от anonymous

Gstreamer в этой схеме нужен только для управления ресурсами. Если мне приспичит сделать мастер-процесс, я и сам его могу написать.

liksys ★★★★
() автор топика

Кто-то уже делал что-то очень-очень похожее на libmdbx (в режиме MDBX_UTTERLY_NOSYNC | MDBX_WRITEMAP, since durability не нужно). Гарантированно быстрее сокетов и надежнее велосипедов.

Либо посмотрите как там сделана синхронизация и recovery при помирании процессов (есть на мьютексах, на семафорах и т.д.). Но imho проще взять как ACId как есть.

anonymous
()

Если тебе нужен примитив мьютекса, а не полноценного семафора. Обычный pthread_mutex c включенными атрибутом robust должен помочь. Но там есть своя специфика. Надо читать документацию.

pathfinder ★★★★
()

Если тебе нужен примитив мьютекса, а не полноценного семафора. Обычный pthread_mutex c включенными атрибутом robust должен помочь. Но там есть своя специфика. Надо читать документацию.

pathfinder ★★★★
()

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

Может не мучится и вместо семафора использовать транзакции?

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

Блокчейн, машин лёрнинг, сноубординг, дискотека?

izzholtik ★★★
()
24 декабря 2021 г.

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

По моему гадание на гуще. Добавить явный запрос «ты живой?» «да я жив!» и всё. А если ответа нету то подох ибо обязан отвечать. Как сделать запрос вопрос десятый, главное что-бы всё явно было, а не может отвалилося, а может нет.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Ну так о том и речь, что решение плохое. Я в итоге сделал flock() и доволен, а на состояние клиента в принципе плевать.

liksys ★★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

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

liksys ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.