Boost.Thread Утверждение / Сбой в Windows во время win32 :: WaitForSingleObject - PullRequest
2 голосов
/ 04 марта 2011

У меня редко встречается проблема в моем коде, когда срабатывает утверждение, включая библиотеку 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.

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

1 Ответ

3 голосов
/ 04 марта 2011

Полагаю, вам будет очень сложно дать точный ответ на вашу проблему, но, похоже, у вас проблема с повреждением кучи, вы пытались использовать AppVerifier с включенным обычным pageheap?Если затем вы подключите к процессу отладчик и обнаружите повреждение кучи, то он, возможно, сломается при обнаружении поврежденного блока кучи, и вы даже сможете посмотреть на стек вызовов выделенного кода.

edit: если вы используете WinDbg, вы можете также поставить условную точку останова на прерывание WaitForSingleObject (или любой другой функции) только в случае сбоя вызова и затем проверить последнюю ошибку, например: bp kernel32! WaitForSingleObject "gu; .if (eax == 0) {g} " -> это сообщит отладчику в точке останова i) выполнить до конца функции (gu) и ii) проверить возвращаемое значение (сохраненное в регистре EAX) и продолжить выполнение(г) если бы все было хорошо.Если возвращается ошибка, вы можете проверить значение GetLastError () с помощью команды расширения ! Gle .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...