Механизмы блокировки для согласованности совместно используемой памяти - PullRequest
9 голосов
/ 18 июня 2010

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

Итак, проведя некоторые исследования, я обнаружил, что семафоры System V имеют флаг SEM_UNDO, который можно вернутьсостояние блокировки при сбое программы, но это не гарантирует работу.Другой вариант - отслеживать PID всех процессов, которые могут использовать разделяемую память, и контролировать их, если происходит что-то неприятное, но я не уверен, что это правильный подход к моей проблеме.

Есть идеи??:)

Редактировать: для пояснения нашему приложению нужен какой-то механизм IPC с наименьшей возможной задержкой.Итак, я открыт для механизмов, которые могут справиться и с этим требованием.

Ответы [ 5 ]

3 голосов
/ 19 июня 2010

Итак, проведя некоторые исследования, я обнаружил, что у семафоров System V есть флаг SEM_UNDO, который может вернуть состояние блокировки в случае сбоя программы, но это не гарантирует работу.

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

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

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

Вторая модель - копировать структуры shm в локальной памяти и сохранять блокировку для всей транзакции. Когда транзакция фиксируется, перед снятием блокировки просто скопируйте структуры из локальной памяти в общую память. Вероятность сбоя приложения во время копирования ниже, а вмешательство внешних сигналов может быть заблокировано с помощью sigprocmask(). (Блокировка в этом случае лучше хорошо распределить по данным. Например, я видел тесты с набором из 1000 блокировок для 10 миллионов записей в ШМ, к которым получают доступ 4 параллельных процесса.)

2 голосов
/ 18 июня 2010

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

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

1 голос
/ 18 июня 2010

Вы можете использовать мьютекс pthread в разделяемой памяти pthread_mutexattr_setpshared (http://linux.die.net/man/3/pthread_mutexattr_setpshared)

Также вы можете попробовать использовать фьютексы непосредственно, см. http://people.redhat.com/drepper/futex.pdf и http://lxr.linux.no/#linux+v2.6.34/Documentation/robust-futexes.txthttp://www.kernel.org/doc/man-pages/online/pages/man7/futex.7.html и http://www.kernel.org/doc/man-pages/online/pages/man2/futex.2.html в частности, второе, поскольку в нем говорится о том, чтобы заставить ядро ​​освободить его, когда умирает процесс, его удерживающий.

Также я думаю, что возможно сделать блокировки pthreadsНадежные / CVs, что является лучшей идеей, так как тогда все для обработки надежных блокировок сделано для вас (в даже отдаленно современном дистрибутиве следует использовать надежные фьютексы, описанные в http://lxr.linux.no/#linux+v2.6.34/Documentation/robust-futexes.txt для pthread_mutex IIRC, поскольку это былов ядре довольно долго, но вы можете убедиться, что вам ничего не нужно делать, чтобы сделать ваш pthread_mutex надежным)

1 голос
/ 18 июня 2010

Мне было бы интересно узнать, какой источник вы использовали, который сказал, что SEM_UNDO не гарантированно будет работать. Я не слышал этого раньше. Кажется, я помню, что читал статьи, в которых утверждалось, что SYSV IPC в Linux в целом содержит ошибки, но это было довольно давно. Мне интересно, является ли ваша информация просто артефактом прошлого.

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

Наконец, я добавлю шаг для очередей сообщений. Они могут не соответствовать вашим требованиям к скорости, но обычно они не намного медленнее, чем разделяемая память. По сути, они в любом случае делают все, что вам нужно делать вручную с SM, но ОС делает все это под прикрытием. Вы получаете почти такую ​​же скорость благодаря синхронизации, атомарности, простоте использования и полностью проверенному механизму бесплатно.

1 голос
/ 18 июня 2010

Когда вы заявили, что семафоры не могут чисто обрабатывать процессы, я был немного удивлен. Такая поддержка кажется довольно фундаментальной! Глядя на страницу руководства semop как в моей системе Ubuntu 10.4, так и в Интернете здесь , похоже, говорит о том, что все должно быть в порядке. Надеюсь, что память, используемая для хранения счетчика SEM_UNDO, хранится в пространстве ядра и, следовательно, защищена от ошибочных операций записи в память.

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

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