LINUX.ORG.RU

[System V] Семафоры и Ко


0

2

Мне понадобилось как-то на неделе написать кроссплатформенный семофор (именованный, то есть для межпроцессной синхронизации) со всеми вытекающими. После некоторого анализа того, что и где имеется, решил остановиться на интерфейсе System V (более распространенный, а вояки наши любят использовать что-нибудь подревнее) для unix-систем, для Windows-систем, конечно же, использовать родной API. В итоге все получилось и работает, но у меня возникло несколько вопросов и наблюдений.

То, что API System V неуклюж и несколько перегружен - не вызывает сомнений, хотя, через денек, начинаешь привыкать. Но проблемы вытекают напрямую из этой самой System V. Во-первых, надо создавать для каждого IPC-объекта (семафор, разделяемая память, с другим еще не возился) свой файл и по нему генерить заветный key_t. Почему нельзя было использовать обычную буквенную последовательность, как это, например, сделано в Windows? Да, я знаю про POSIX-интерфейс к IPC, но и там жизнь не легче. Стандартом де-факто в мире UNIX является System V, поэтому от этого и решено было отталкиваться. Поэтому приходиться следить за созданным файлом. Это раз.

У семафора есть такая проблема, что им владеет, фактически, система, а не процессы. То есть, если вдруг процессы сегфолтнутся и семафор будет в этот момент в залоченном состоянии, то при следующем запуске приложения и обращения к семафору я опять получу уже залоченный семафор. Например в Windows семафором «владеют» процессы, и как только все процессы завершатся или «отпустят» семафор, он удаляется. Все просто и надежно. Есть ли какой-то Ъ-вэй решить этот косяк в UNIX-системах? Только, пожалуйста, без костылей типа мастер-процесса следящего за другими, или запускать один процесс всегда первым и т.д. Есть ли что-нибудь готовое на системном уровне? Только не надо говорить про SEM_UNDO - связанные с этим косяки всем известны, равно как и системно-зависимая реализация.

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

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

★★★★
Ответ на: комментарий от mikki

>>В общих моментах, получите вариацию loсking-free синхронизации.

Да, спасибо за идею. В принципе, звучит безболезненно :)

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

>Да, спасибо за идею. В принципе, звучит безболезненно :)

Я бы все таки посоветовал сделать через pipe. Я конечно понимаю, что очень хочется проявить свою инженерную смекалку, написать самому сложные примитивы ipc. Но надо понимать, что при shared memory будет очень плохая изоляция двух приложений друг от друга. Это может привести к тому, что из-за ошибок в одном приложении может упасть другое. Будет нелегко доказать, что баг содержится в чужой программе, даже если это будет действительно так. В конце концов такое решение может привести к тому, вы с этим НИИ будете постоянно кидаться говном друг в друга.

pipe ИМХО достаточно быстрый и простой механизм ipc. Тем более что ты, как я понял, будешь писать его аналог - одностороннюю очередь.

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

Плюсую к пайпу, будет примерно тоже самое по функциональности, но гораздо проще и надёжнее.

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

>>pipe ИМХО достаточно быстрый и простой механизм ipc. Тем более что ты, как я понял, будешь писать его аналог - одностороннюю очередь.

У меня еще стоит задача кросплатформенности всего того, что мы делаем. На винде же пайпы почти как сокеты локальные.

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

(после данного сообщения тему пока не читал)

Ну смотри, первый процесс читает флаг из памяти и видит, что доступ свободен, в это время флаг изменяет другой процесс


обходится очень просто:
инкремент семафора _до_ его проверки.
алгоритм:

volatile int *sem;
try_lock:
++*sem; // атомарный инкремент
if(*sem>1) //был занят или конкуренция
{
--*sem;
usleep(rand());
goto try_lock;
}

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