Необработанное исключение при использовании std:: mutex вместо boost:: mutex
Я пытаюсь избавиться от некоторых зависимостей boost в моем коде и вместо этого использовать новые возможности С++ 11 (Visual Studio 2013).
В одном из моих компонентов я использовал boost::mutex
вместе с boost::lock_guard<boost::mutex>
, и все работало нормально. Когда я использую std::mutex
вместе с std::lock_guard<std::mutex>
вместо этого, я получаю следующую ошибку при возврате из main()
.
Необработанное исключение в 0x7721E3BE (ntdll.dll) в файле GrabberTester.exe: 0xC0000005: место чтения нарушения доступа 0xA6A6B491.
Реальный проект довольно сложный и поэтому трудно представить полный пример рабочего кода, чтобы воспроизвести эту проблему. В моем реальном проекте мьютексы используются в общей библиотеке, которая загружается во время выполнения (но которая уже должна быть выгружена к моменту возвращения из main()
).
Мои вопросы:
- Существуют ли
boost::mutex
и std::mutex
, чтобы вести себя абсолютно одинаково?
- Если нет, каковы различия? Что мне нужно иметь в виду при использовании
std::mutex
вместо boost::mutex
?
- В общей библиотеке я создаю потоки с помощью рамки
boost::thread
. Может ли быть, что std::mutex
можно использовать только с std::thread
и несовместимо с boost::thread
s?
Изменить:
Еще одна вещь, которую я заметил: когда я выгружаю динамически загруженную разделяемую библиотеку, это занимает некоторое время. (DLL обращается к аппаратным средствам, и требуется некоторое время, чтобы закрыть все чисто). Когда я переключаюсь на std::mutex
, однако, похоже, что DLL можно выгружать почти сразу, но затем программа вылетает при возврате из main()
. У меня создалось впечатление, что проблема с std::mutex
в частности связана с DLL.
Изменить 2:
И приложение, и DLL только что были созданы в конфигурации Debug с помощью набора инструментов v120 и статически связаны с библиотекой времени выполнения (/MTd).
Изменить 3:
Ниже вы можете найти столбец. Исключение, похоже, происходит где-то в драйвере. Только случайно я понял, что это связано с тем, какую реализацию мьютекса я использую.
ntdll.dll!7721e3be()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7721e023()
kernel32.dll!76b014ad()
msvcr100.dll!71b0016a()
PS1080.dll!oniDriverDestroy() Line 29
OpenNI2.dll!oni::implementation::DeviceDriver::~DeviceDriver() Line 95
OpenNI2.dll!oni::implementation::Context::shutdown() Line 324
OpenNi2Grabber.dll!openni::OpenNI::shutdown() Line 2108
OpenNi2Grabber.dll!GrabberSingletonImpl::~GrabberSingletonImpl() Line 46
OpenNi2Grabber.dll!`GrabberSingletonImpl::getInstance'::`2'::`dynamic atexit destructor for 'inst''()
OpenNi2Grabber.dll!doexit(int code, int quick, int retcaller) Line 628
OpenNi2Grabber.dll!_cexit() Line 448
OpenNi2Grabber.dll!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 169
OpenNi2Grabber.dll!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 399
OpenNi2Grabber.dll!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 340
ntdll.dll!7722b990()
ntdll.dll!77249bad()
ntdll.dll!77249a4f()
kernel32.dll!76b079ed()
GrabberTester.exe!__crtExitProcess(int status) Line 776
GrabberTester.exe!doexit(int code, int quick, int retcaller) Line 678
GrabberTester.exe!exit(int code) Line 417
GrabberTester.exe!__tmainCRTStartup() Line 264
GrabberTester.exe!mainCRTStartup() Line 165
kernel32.dll!76b0338a()
ntdll.dll!7722bf32()
ntdll.dll!7722bf05()
Изменить 4:
Возможно, это ошибка в OpenNI2 SDK, которая может наблюдаться только в этих особых условиях. Поэтому я добавил к этому вопросу тег openni. Но остается вопрос: почему он работает с boost::mutex
, но не с std::mutex
?
Ответы
Ответ 1
Проблема, скорее всего, это статический ад, я недавно прошел почти то же самое. Вот что происходит:
- У вас есть статический мьютекс (может быть членом статического класса).
- Код doexit() начинает очищать ваши статические вещи.
- Мьютекс уничтожается где-то в doexit()
- Что-то использует мьютекс после его уничтожения, часто в деструкторе.
Проблема в том, что вы действительно не знаете порядок уничтожения для статических объектов. Поэтому, если у вас есть:
static std::mutex staticMutex;
void someFunction()
{
std::unique_lock<std::mutex> lock(staticMutex);
doSomethingAwesome();
}
....
StaticObjA::~StaticObjA()
{
someFunction();
}
Затем ваш статический мьютекс МОЖЕТ быть удален/уничтожен/deadbeef при вызове ~ StaticObjA(). Проблема усугубляется, когда объекты определены в разных единицах компиляции (т.е. Определены в разных файлах).
Моя рекомендация для решения состоит в том, чтобы попытаться уменьшить зависимость от статических объектов, вы можете попробовать иметь один статический объект, который заботится о строительстве/уничтожении всего остального, чтобы вы могли контролировать порядок событий. Или просто не используйте статику вообще.
Ответ 2
Я добавляю ту же проблему, и то, что решено, - это полная ручная очистка + перестройка! Проверьте удаление всех файлов .obj,.dll,.lib.
Ответ 3
Не используйте std:: mutex (или recursive_mutex,...) от Mircosoft!!!!
У меня были подобные проблемы. Я использую VS2012.
Если вы используете std:: mutex в dll, вы не должны выгружать эту DLL. Потому что вы получаете поведение undefined. (в моем случае 0xC0000005: местоположение чтения нарушения доступа....).
Или вы не можете выгрузить DLL. (может "? runtime?" увеличивает счетчик загрузки. Double FreeLibrary() выгружает dll)
Ответ 4
У меня была аналогичная проблема, когда мой код попытался заблокировать дважды один и тот же мьютекс: функция приобрела блокировку, а затем вызвала другую функцию, пытающуюся получить блокировку на том же глобальном/статическом мьютеке.
mutex queueMutex;
void f1()
{
lock_guard<mutex> guard(queueMutex);
f2();
}
void f2()
{
lock_guard<mutex> guard(queueMutex); //unhandled exception!
}