2013-04-02 2 views
5

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

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

Без дальнейших церемоний, вот что у меня есть:

#include <boost/interprocess/sync/named_recursive_mutex.hpp> 
#include <boost/interprocess/sync/scoped_lock.hpp> 

typedef boost::interprocess::named_recursive_mutex MyMutex; 
typedef boost::interprocess::scoped_lock<MyMutex> ScopedLock; 

MyMutex* pGate = reinterpret_cast<MyMutex*>(new MyMutex(boost::interprocess::open_or_create, "MutexName"); 

{ 
    // ScopedLock lock(*pGate); // this blocks indefinitely 
    boost::posix_time::ptime timeout(boost::posix_time::microsec_clock::local_time() + boost::posix_time::seconds(10)); 
    ScopedLock lock(*pGate, timeout); // a 10 second timeout that returns immediately if the mutex is abandoned ????? 
    if(!lock.owns()) { 
     delete pGate; 
     boost::interprocess::named_recursive_mutex::remove("MutexName"); 
     pGate = reinterpret_cast<MyMutex*>(new MyMutex(boost::interprocess::open_or_create, "MutexName"); 
    } 
} 

Это, по крайней мере, это идея. Три интересных момента:

  • Когда я не использовать объект тайм-аут, и мьютекс брошено, ScopedLock CTOR блоки на неопределенное время. Это ожидалось.
  • Когда я действительно использую тайм-аут, а мьютекс заброшен, ScopedLock ctor немедленно возвращается и сообщает мне, что он не имеет мьютекса. Хорошо, возможно, это нормально, но почему он не ждет 10 секунд, о которых я тоже рассказываю?
  • Когда мьютекс не заброшен, и я использую таймаут, ScopedLock ctor все равно возвращается немедленно, сообщая мне, что он не может заблокировать или взять на себя ответственность за мьютекс, и я прохожу через движения по удалению мьютекс и переделку. Это совсем не то, что я хочу.

Итак, что мне не хватает при использовании этих объектов? Возможно, это смотрит мне в лицо, но я не вижу этого, и поэтому я прошу помощи.

Следует также упомянуть, что из-за того, как это аппаратное обеспечение работает, если процесс не может получить право собственности на мьютекс в течение 10 секунд, мьютекс заброшен. Фактически, я, вероятно, мог бы подождать всего 50 или 60 миллисекунд, но 10 секунд - это хорошее «круглое» количество щедрости.

Я компиляции на Windows 7 с помощью Visual Studio 2010.

Спасибо, Энди

+2

Не относится к вашему вопросу, но 'reinterpret_cast ' s в вашем примере не нужны (не знаю, почему они там). –

+0

@GaborMarton Я думаю, что правильно использую функцию remove(). Проверьте код еще раз. Я удаляю указатель, который, я согласен, не удаляет мьютекс, но тогда я вызываю boost :: interprocess :: named_recursive_mutex :: remove ("MyMutex"). Если я неправильно его использовал, пожалуйста, поправьте меня. Спасибо –

+0

Да, вы правы, просто удалили мой комментарий и обновили мой ответ. Надеюсь, это поможет. –

ответ

4

Когда я не использую объект тайм-аут, и мьютекс брошено, CTOR блоки ScopedLock на неопределенный срок. Ожидается

Лучшее решение для вашей проблемы было бы, если boost имел поддержку надежных мьютексов. Однако Boost в настоящее время не поддерживает надежные мьютексы. Существует только план эмуляции надежных мьютексов, потому что только linux имеет встроенную поддержку. Эмуляция еще только планировалась автором книги Ион Газтанага. Проверить ссылку о возможном взломе из rubust мьютексы в LIBS наддува: http://boost.2283326.n4.nabble.com/boost-interprocess-gt-1-45-robust-mutexes-td3416151.html

Между тем вы можете попытаться использовать атомные переменные в общем сегменте.

Также обратите внимание на эту StackOverflow запись: How do I take ownership of an abandoned boost::interprocess::interprocess_mutex?

Когда я использую тайм-аут, и мьютекс брошено, ScopedLock CTOR возвращается немедленно и говорит мне, что он не является владельцем мьютекса , Хорошо, возможно, это нормально, но почему он не ждет 10 секунд, о которых я тоже рассказываю?

Это очень странно, вы не должны этого делать. Однако: Блокировка по времени может быть реализована с точки зрения блокировки try. Проверьте эту документацию: http://www.boost.org/doc/libs/1_53_0/doc/html/boost/interprocess/scoped_lock.html#idp57421760-bb Это означает, что реализация синхронизированной блокировки может вызывать исключение изнутри и затем возвращает false.

inline bool windows_mutex::timed_lock(const boost::posix_time::ptime &abs_time) 
{ 
    sync_handles &handles = 
     windows_intermodule_singleton<sync_handles>::get(); 
    //This can throw 
    winapi_mutex_functions mut(handles.obtain_mutex(this->id_)); 
    return mut.timed_lock(abs_time); 
} 

Возможно, ручка не может быть получена, поскольку мьютекс заброшен.

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

Я не уверен в этом, но я думаю, что именованный мьютекс реализован с использованием общей памяти. Если вы используете Linux, проверьте файл/dev/shm/MutexName. В Linux дескриптор файла остается действительным до тех пор, пока он не будет закрыт, независимо от того, удалил ли вы сам файл, например. повышение :: межпроцессного :: named_recursive_mutex :: удалить.

+0

Извините за страшную задержку, отметив это как ответ. В основном, из-за переносимости в Boost, мы решили жить с этой «проблемой» на данный момент. –

3

Отъезд BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING и BOOST_INTERPROCESS_TIMEOUT_WHEN_LOCKING_DURATION_MS компиляции флаги. Определите первый символ в коде, чтобы заставить mutexes interprocess выйти из таймаута, а второй - определить продолжительность таймаута.

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

Прошу прощения, что я не могу помочь вам с вашим кодом на данный момент; там что-то не работает.

1

BOOST_INTERPROCESS_ENABLE_TIMEOUT_WHEN_LOCKING не так хорошо. Он выдает исключение и не очень помогает. Чтобы обойти исключительное поведение, я написал этот макрос. Он работает просто хорошо для общего назначения. В этом примере используется named_mutex. Макрос создает фиксированную блокировку с таймаутом, и если блокировка не может быть получена по ИСКЛЮЧИТЕЛЬНЫМ причинам, она затем разблокирует ее. Таким образом, программа может заблокировать ее позже и не замерзает или не сбой немедленно.

#define TIMEOUT 1000 
#define SAFELOCK(pMutex) \ 
    boost::posix_time::ptime wait_time \ 
     = boost::posix_time::microsec_clock::universal_time() \ 
     + boost::posix_time::milliseconds(TIMEOUT); \ 
    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(*pMutex, wait_time); \ 
    if(!lock.owns()) { \ 
     pMutex->unlock(); } 

Но даже это не оптимально, поскольку код, который будет заблокирован, теперь разблокируется разблокированным. Это может вызвать проблемы. Однако вы можете легко расширить макрос. Например. запускать код, только если lock.owns() - true.