Повышенный общий мьютекс не освобождается после выброса исключения - PullRequest
0 голосов
/ 17 августа 2011

Я натолкнулся на странную тупиковую взаимоблокировку Boost (v1.38) в ранее существовавшем приложении .NET (C #, 3.5), которое выполняет вызовы библиотеки C ++. Исключение [правильно] генерируется в точке после получения блокировки чтения, и это исключение остается необработанным вплоть до управляемого кода .NET (где он обрабатывается). Следующий вызов библиотеки c ++, который пытается использовать метод установки, неопределенно зависает при получении уникальной блокировки (предположительно, блокировка чтения не была снята):

ntdll.dll!NtWaitForSingleObject() + 0x15 bytes 
kernel32.dll!WaitForSingleObjectEx() + 0x43 bytes 
kernel32.dll!WaitForSingleObject() + 0x12 bytes 
OurCPPLib.dll!boost::shared_mutex::unlock_upgrade_and_lock() Line 478 + 0x11 bytes C++ 
OurCPPLib.dll!boost::unique_lock<boost::shared_mutex>::unique_lock<boost::shared_mutex>(boost::detail::thread_move_t<boost::upgrade_lock<boost::shared_mutex> > other) Line 788 C++ 
OurCPPLib.dll!boost::upgrade_to_unique_lock<boost::shared_mutex>::upgrade_to_unique_lock<boost::shared_mutex>(boost::upgrade_lock<boost::shared_mutex> & m_) Line 802 + 0x98 bytes C++ 
OurCPPLib.dll!OurClass::SetSomething(double something) Line 95 C++ 

Класс определяет несколько методов Get и Set (читателей / писателей) и реализует их следующим образом:

boost::shared_mutex _calcSharedMutex;

RETURNCODE GetSomething(double& something)
{
    boost::shared_lock<boost::shared_mutex> lock(_calcSharedMutex);
    return _anotherObject->GetSomething(something);
}

RETURNCODE SetSomething(double something)
{
    boost::upgrade_lock<boost::shared_mutex> lock(_calcSharedMutex);
    boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
    return _anotherObject->SetSomething(something);
}

Вызов _anotherObject-> GetSomething () вызовет исключение в редком состоянии:

throw std::invalid_argument("Unknown something");

Кроме того, есть некоторые вызовы в методах get для _anotherObject-> GetSomething (), которые выполняются в пределах try / catch в самой библиотеке C ++, предотвращая возвращение исключения к управляемому коду, и это не вызывает эту тупиковую ситуацию. , Не нарушает ли необработанное исключение разблокировку буст-мьютекса?

Заранее спасибо всем, кто может иметь некоторое понимание!

Ответы [ 2 ]

2 голосов
/ 17 августа 2011

В C ++ не указано, будет ли стек разматываться при возникновении необработанного исключения. Некоторые реализации делают это (вызывая деструкторы и все остальное, что должно произойти), в то время как другие этого не делают. Я не знаю точно, как C ++ / CLI обрабатывает это, но если часть C ++ видит исключение как необработанное, то возможно, что оно не размотает стек и, таким образом, не вызовет деструктор и не освободит мьютекс .

(если это так, просто перехват и повторное создание исключения в коде C ++ должно решить проблему)

Но это всего лишь предположение. Я никогда не использовал C ++ / CLI, и я понятия не имею, как распространяются исключения между собственным и управляемым кодом.

0 голосов
/ 19 октября 2011

В 2.0 CLR есть ошибка, которая не позволяет стеку раскручиваться при обработке собственного исключения в управляемом коде.

Microsoft Connect: / Ehsc & / Eha & разматывание стека

Переключение управляемого исполняемого файла для запуска на 4.0 CLR устранило проблему.

В качестве примечания, нативная библиотека C ++ вызывается из управляемой библиотеки C #, которая ориентирована на 2.0 CLR. Управляемая сборка может продолжать ориентироваться на 2.0 CLR, поскольку она будет выполняться на CLR без ошибок исполняемого файла (4.0), но будет выполняться в режиме совместимости 2.0.

...