boost::interprocess::message_queue сбой в работе очереди
От: varga  
Дата: 28.05.10 06:24
Оценка:
Привет, всем!

Появилась проблема при использовании boost::interprocess::message_queue(boost 1.42) —
это именованная глобальная очередь сообщений, в которую можно писать/читать из разных процессов

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

Если один из процессов аварийно завершается (ловит сигфолт) а в это время один из его потоков
выполенял операции try_send/try_receive в это же самое время, то очередь переходит в "заблокированное состояни".

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

Запустил под отладчиком процесс после очередного фатального завершения процесса и оказалось, что поток блокируется
на функции message_queue::do_send(block_t block, ...) на инструкции:

line 448: scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);



Как я понимаю фатально завершившийся поток выполнил lock для межпроцессорного мьютекса p_hdr->m_mutex, а соответствующий
unlock выполнить не успел.

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

Существует ли возможность определить, что очередь оказалась в такой "нештатной" блокировке, и вернуть очередь в рабочее состояние?


--
Дмитрий
Re: boost::interprocess::message_queue сбой в работе очереди
От: remark Россия http://www.1024cores.net/
Дата: 28.05.10 08:56
Оценка: 4 (3)
Здравствуйте, varga, Вы писали:

V>
V>line 448: scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
V>


V>Как я понимаю фатально завершившийся поток выполнил lock для межпроцессорного мьютекса p_hdr->m_mutex, а соответствующий

V>unlock выполнить не успел.

V>Я так понимаю проблема состоит в том, что межпроцессорный мьютекс никак не связан с процессом, который его использует,

V>поэтому падение процесса не приводит к его разблокировке.

V>Существует ли возможность определить, что очередь оказалась в такой "нештатной" блокировке, и вернуть очередь в рабочее состояние?



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

В целом такая возможность есть, такая синхронизация называется robust IPC. В Windows мьютексы всегда robust, при смерти владеющего процесса WaitForSingleObject() вернёт WAIT_ABANDONED, это значит, что процессу надо "восстановить" состояние после умершего процесса до разблокировки мьютекса. В POSIX мьютекс надо явно инициализировать как robust с помощью pthread_mutexattr_setrobust(), тогда процесс будет получать EOWNERDEAD после смерти владеющего процесса, и после восстановления надо явно пометить данные как консистентные с помощью pthread_mutex_consistent().

Только учти, что что бы "восстанавливать" данные, вся работа под мьютексом должна быть написана в стиле lock-free (с помощью упорядоченных атомарных операций), т.к. данные после обычного C/C++ кода восстановить не удастся.
Плюс есть такие моменты, как например нельзя отдельно выделить память под сообщение, а потом отдельно поместить сообщение в очередь — при таком подходе начнутся утечки памяти. Выделение памяти и помещение в очередь должны быть так или иначе связаны, что бы их можно было целиком восстановить (в частности освободить память, если сообщение так и не попало в очередь).



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: boost::interprocess::message_queue сбой в работе очереди
От: blackwater  
Дата: 28.05.10 09:08
Оценка:
Здравствуйте, varga, Вы писали:

V>Привет, всем!


V>Если один из процессов аварийно завершается (ловит сигфолт) а в это время один из его потоков

V>выполенял операции try_send/try_receive в это же самое время, то очередь переходит в "заблокированное состояни".
...
V>Как я понимаю фатально завершившийся поток выполнил lock для межпроцессорного мьютекса p_hdr->m_mutex, а соответствующий
V>unlock выполнить не успел.

V>Я так понимаю проблема состоит в том, что межпроцессорный мьютекс никак не связан с процессом, который его использует,

V>поэтому падение процесса не приводит к его разблокировке.

V>Существует ли возможность определить, что очередь оказалась в такой "нештатной" блокировке, и вернуть очередь в рабочее состояние?


А можно вопрос.

Ты пробовал назначить обработчик сигнала на SIGSEGV и в нем проверить вот тот самый залоченный межпроцессный mutex и если он залочен, то его разлочить или дождаться пока он разлочится и там уже падать?

А так согласен, падение процесса не приводит к разблокировке залоченного IPC мьютекса.
Re[2]: boost::interprocess::message_queue сбой в работе очер
От: varga  
Дата: 28.05.10 09:19
Оценка:
Здравствуйте, blackwater, Вы писали:

B>А можно вопрос.


B>Ты пробовал назначить обработчик сигнала на SIGSEGV и в нем проверить вот тот самый залоченный межпроцессный mutex и если он залочен, то его разлочить или дождаться пока он разлочится и там уже падать?


B>А так согласен, падение процесса не приводит к разблокировке залоченного IPC мьютекса.


Обработчик сигнала SIGSEGV есть, но он не "лезит" во внутренности message_queue. Даже если будет применено такое решение, то гарантии целостности очереди нет.

А если будет получен сигнал SIGKILL то обработчик и вовсе не сработает.
Re[2]: boost::interprocess::message_queue сбой в работе очер
От: zaufi Земля  
Дата: 28.05.10 09:31
Оценка: 4 (2)
Здравствуйте, remark, Вы писали:

V>>Существует ли возможность определить, что очередь оказалась в такой "нештатной" блокировке, и вернуть очередь в рабочее состояние?


R>Если это именно мьютекс, то ОС освободит его при смерти процесса. Скорее всего там используется не мьютекс, а семафор или что-то самопальное.

нет там внутри этой эмуляции очереди обыкновенный pthread_mutex_t созданный в шареной памяти с аттрибутом PTHREAD_PROCESS_SHARED

т.е. при смерти одного процесса еси не почистить эту саму память (что конечно же грязный хак) он останется там залоченым

фигня в том что из прикладного кода добраться до этого mutex'a топикстартеру буит аццки не просто (если вообще возможно... ну конечно всегда можно похакать буст %) ... так что второй совет в этом thread'e (повеситься на SIGSEGV и делать unlock) также реализуем с невероятным трудом

теперь об эмуляции: заглянув в исходнеки был разочарован что message_queue этот на сам деле ни какой не POSIX message queue (see mans: mq_open, mq_close, mq_send, mq_receive), а тупо шареная память и интерпроцессный mutex...

топикстартеру рекомендую ознакомиться с `man 7 mq_overview`. от себя добавлю что в POSIX message queue ни кааких локов не требуется вв юзерском коде пользоваться легко и удобно (с помощью простецких С++ных врапперов конечно же %) которые к слову говоря сильно проще чем в бусте накрученная эмуляция)... ну и кроме всего прочего нативные message queue умеют уведомлять процесс (каким скажешь сигналом) о пришедшем сообщении (не нада ничо полоть)
Re[3]: boost::interprocess::message_queue сбой в работе очер
От: blackwater  
Дата: 28.05.10 09:35
Оценка:
Здравствуйте, varga, Вы писали:

V>Здравствуйте, blackwater, Вы писали:


B>>А можно вопрос.


B>>Ты пробовал назначить обработчик сигнала на SIGSEGV и в нем проверить вот тот самый залоченный межпроцессный mutex и если он залочен, то его разлочить или дождаться пока он разлочится и там уже падать?


V>Обработчик сигнала SIGSEGV есть, но он не "лезит" во внутренности message_queue. Даже если будет применено такое решение, то гарантии целостности очереди нет.


Так а почему не лезет. Я вот и спрашиваю про обоснование. Я знаю, что есть ограниченный набор функций libc которые можно вызывать в обработчике сигнала, другие не стоит вызывать. А у вас какая причина это не делать? Может пусть зайдет и разлочит? Или дождется пока другой поток его разлочит. Про гарантии целостности очереди я не понял. Что мешает достичь этих гарантий если ты напишешь такой обработчик сигнала?


V>А если будет получен сигнал SIGKILL то обработчик и вовсе не сработает.

Как раз это самый простой случай как мне кажется. SIGKILL посылается командой kill -9? Тогда пусть человек (или скрипт) также делают ipcrm. Ведь kill -9 они сами делали. Или запускают твое приложение с каким-нибудь дополнительным ключом, чтобы оно само удалило этот IPC мьютекс.
Re[3]: boost::interprocess::message_queue сбой в работе очер
От: varga  
Дата: 28.05.10 09:45
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>Здравствуйте, remark, Вы писали:


Z>нет там внутри этой эмуляции очереди обыкновенный pthread_mutex_t созданный в шареной памяти с аттрибутом PTHREAD_PROCESS_SHARED


Z>т.е. при смерти одного процесса еси не почистить эту саму память (что конечно же грязный хак) он останется там залоченым


Z>фигня в том что из прикладного кода добраться до этого mutex'a топикстартеру буит аццки не просто (если вообще возможно... ну конечно всегда можно похакать буст %) ... так что второй совет в этом thread'e (повеситься на SIGSEGV и делать unlock) также реализуем с невероятным трудом


Z>теперь об эмуляции: заглянув в исходнеки был разочарован что message_queue этот на сам деле ни какой не POSIX message queue (see mans: mq_open, mq_close, mq_send, mq_receive), а тупо шареная память и интерпроцессный mutex...


Boost видимо из-за своей кроссплатформенности не может использовать нативно POSIX message queue. Под windows этот вариант не прокатит.

Z>топикстартеру рекомендую ознакомиться с `man 7 mq_overview`. от себя добавлю что в POSIX message queue ни кааких локов не требуется вв юзерском коде пользоваться легко и удобно (с помощью простецких С++ных врапперов конечно же %) которые к слову говоря сильно проще чем в бусте накрученная эмуляция)... ну и кроме всего прочего нативные message queue умеют уведомлять процесс (каким скажешь сигналом) о пришедшем сообщении (не нада ничо полоть)


У нас проект в проекте не рекомендуется использовать чистый POSIX. Поэтому используется Boost.
Re[4]: boost::interprocess::message_queue сбой в работе очер
От: remark Россия http://www.1024cores.net/
Дата: 03.06.10 09:50
Оценка:
Здравствуйте, varga, Вы писали:

Z>>топикстартеру рекомендую ознакомиться с `man 7 mq_overview`. от себя добавлю что в POSIX message queue ни кааких локов не требуется вв юзерском коде пользоваться легко и удобно (с помощью простецких С++ных врапперов конечно же %) которые к слову говоря сильно проще чем в бусте накрученная эмуляция)... ну и кроме всего прочего нативные message queue умеют уведомлять процесс (каким скажешь сигналом) о пришедшем сообщении (не нада ничо полоть)


V>У нас проект в проекте не рекомендуется использовать чистый POSIX. Поэтому используется Boost.


А если Boost не содержит необходимых компонент?
Если нужна именно robust очередь (что б переживала крэши и насильные пребивания процессов; а зачем тогда вообще IPC, если этого нет?..), то варианта 2. Первый — тормозной, но простой — использовать mq, пайпы, сокеты и т.д. Второй — быстрый, но сложный — писать с нуля robust очередь.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: boost::interprocess::message_queue сбой в работе очер
От: remark Россия http://www.1024cores.net/
Дата: 03.06.10 09:56
Оценка:
Здравствуйте, blackwater, Вы писали:

B>Так а почему не лезет. Я вот и спрашиваю про обоснование. Я знаю, что есть ограниченный набор функций libc которые можно вызывать в обработчике сигнала, другие не стоит вызывать. А у вас какая причина это не делать? Может пусть зайдет и разлочит? Или дождется пока другой поток его разлочит. Про гарантии целостности очереди я не понял. Что мешает достичь этих гарантий если ты напишешь такой обработчик сигнала?


Мешает это сделать то, что это сделать нельзя. Данные после обычного С/C++ кода восстановить нельзя. Что бы это можно было сделать, очередь должна работать по какому-то специальному алгоритму, который предусматривает восстановление, и очень аккуратно реализована с помощью упорядоченных атомарных операций. Только в этом случае её можно будет восстановить.


V>>А если будет получен сигнал SIGKILL то обработчик и вовсе не сработает.

B>Как раз это самый простой случай как мне кажется. SIGKILL посылается командой kill -9? Тогда пусть человек (или скрипт) также делают ipcrm. Ведь kill -9 они сами делали. Или запускают твое приложение с каким-нибудь дополнительным ключом, чтобы оно само удалило этот IPC мьютекс.

Разлочивание мьютекса — это меньшая (практически нулевая) часть проблемы. robust POSIX мьютексы и Win32 мьютексы вообще сами разлочиваются. И дальше начинается самое интересное.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.