У меня редко встречается проблема в моем коде, когда срабатывает утверждение, включая библиотеку Boost.Thread. Мне не удалось воспроизвести эту проблему на отдельном примере, и я не знаю, что является ее причиной, поэтому трудно привести пример случая. Я надеюсь, что любой, кто знаком с внутренними компонентами boost.thread, сможет помочь.
Вот что я знаю:
- Проблема возникает, когда объявляется
boost::lock_guard<boost::recursive_mutex>
(или варианты unique_lock и обычного нерекурсивного мьютекса).
- Это происходит в функции обработчика для Boost.Asio. В стеке находится поток, который выполняет
io_service::run
, связку для вызова функции обратного вызова Asio, за которой следует моя функция обратного вызова (запускаемая вызовом async_write). Первая строка этой функции - это объявление lock_guard<>
, вызывающее проблему.
this
внутри моей функции действует и не был удален или что-то в этом роде. Отладчик показывает, что он указывает на действительные данные. Мьютекс, который заблокирован в моей функции handle_write
, также защищает от удаления памяти, используемой функцией обработки.
- Это прекрасно работает, я бы сказал, 9999 раз из 10000, с интенсивным многопоточным использованием. Проблема возникает с той же частотой, если я уменьшу количество потоков, используемых приложением, до одного потока, который обрабатывает вызовы Asio run (), и основного потока пользовательского интерфейса.
- Первая строка моего кода вызывает метод мьютекса
lock()
(в ctor boost::unique_lock<>
), затем вызывает lock()
in boost::detail::basic_recursive_mutex_impl
, который вызывает метод lock()
boost::detail::basic_timed_mutex
.
В Boost 1.46 утверждение (BOOST_VERIFY
) находится на строке 78 файла basic_timed_mutex.hpp, которая вызывает win32 :: WaitForSingleObject:
do
{
BOOST_VERIFY(win32::WaitForSingleObject(
sem,::boost::detail::win32::infinite)==0);
clear_waiting_and_try_lock(old_count);
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
- В то время, когда код Boost.Thread ожидает блокировки мьютекса (что делает этот путь кода, который использует
WaitForSingleObject
), никакой другой поток не удерживает мьютекс (по крайней мере, в то время, когда происходит утверждение, и можно проверить в отладчике). Это странно, потому что он должен иметь возможность получить блокировку, не дожидаясь, пока другой поток откажется от управления.
- Вещи выглядят очень странно, рассматривая членов мьютекса. Это значения всех локальных переменных и переменных-членов (если не указано иное, они одинаковы каждый раз, когда это происходит):
sem
- 0xdddddddddddddddd - Это всегда одно и то же при каждом сбое.
lock_acquired
- false .
old_count
- 0xdddddddddddddddd .
this
- представляется действительным, и его адрес совпадает с тем, что имеет объект, в котором он находится (объект, для которого handle_write
является методом). Похоже, он не был удален или каким-либо образом испорчен.
this->active_count
- Отрицательное целое число, диапазоны, которые я видел, были между -570000000 и -580000000.
this->event
- 0xdddddddddddddddd .
К сожалению, я не вижу результата вызова WaitForSingleObject
. Запись MSDN в функции API указывает четыре возможных типа возврата, два из которых невозможны в этом сценарии. Поскольку WaitForSingleObject
вызывается с недопустимым дескриптором события (sem
= 0xdddddddddddddddd
), я предполагаю, что он возвращает 0xFFFFFFFF
, и GetLastError будет указывать, что был предоставлен недопустимый дескриптор.
Таким образом, реальная проблема заключается в том, что get_event()
метод basic_timed_mutex
возвращает 0xdddddddddddddddd
. Однако запись *1010* MSDN для CreateEvent
(которую в конечном итоге использует get_event()
) говорит мне, что она возвращает либо действительный дескриптор события, либо NULL
.
Опять же, это, вероятно, лучшее описание проблемы, которую я могу предоставить, поскольку она не может быть надежно воспроизведена за пределами этого конкретного приложения. Я надеюсь, что у кого-то есть идеи относительно того, что может быть причиной этого!