WaitForSingleObject () - PullRequest
       6

WaitForSingleObject ()

3 голосов
/ 08 июня 2009

Я застрял в действительно удивительной проблеме здесь. Код такой, как показано ниже.

class A
{
   public:  
   A(){  
         m_event =  CreateEvent(NULL, false, false, NULL);       // create an event with initial value as non-signalled
         m_thread = _beginthread(StaticThreadEntry, 0, this);    // create a thread 
      }

   static void StaticThreadEntry(A *  obj) {  obj->ThreadEntry();  }

   void ThreadEntry();
};

void A::ThreadEntry()
{
     WaitforSingleObject(m_event,INFINITE);
}


int main()
{
        A a;

        SetEvent(m_event);     // sets the event to signalled state which causes the running thread to terminate 

        WaitForSingleObject(m_thread, INFINITE);  // waits for the thread to terminate

        return 0;
 } 

Проблема:

При выполнении приведенного выше кода иногда (1 из 5) он зависает, и элемент управления застревает в вызове WaitforSingleObject () (внутри основной функции). Код всегда вызывает функцию SetEvent (), чтобы поток будет прерван до вызова функции Wait ().

Не вижу причины, по которой оно должно зависать?

Ответы [ 7 ]

17 голосов
/ 08 июня 2009

Проблема в том, что вы используете API _beginthread. Вы не можете использовать дескриптор, возвращенный из этой функции с функциями ожидания Win32. Вы должны использовать _beginthreadex или CreateThread. Из MSDN:

В случае успеха каждая из этих функций возвращает дескриптор вновь созданного потока; однако, если новый созданный поток завершается слишком быстро, _beginthread может не вернуть действительный дескриптор ...

Вы ... можете использовать дескриптор потока, возвращаемый _beginthreadex, с API-интерфейсами синхронизации, чего нельзя сделать с _beginthread.

2 голосов
/ 08 июня 2009

Я не вижу проблем в коде (при условии, что событие создано до того, как поток запущен в конструкторе).

  • Событие является событием автоматического сброса и начальное состояние не сигнализируется.
  • Дочерняя нить должна ждать, пока событие сигнализируется.
  • Главный поток будет сигнализировать о событии и ожидает завершения дочернего процесса.

Предполагая, что это полный код (а не пример кода), он выглядит довольно хорошо для меня.

Я предлагаю вам использовать Process Explorer для наблюдения за состоянием события.

EDIT

Существует небольшая вероятность того, что дочерний поток будет прерван до того, как основной поток будет ожидать его дескриптора. Если дескриптор повторно используется для некоторых других объектов ядра, и основной поток будет ждать бесконечно. Попробуйте продублировать дескриптор, используя DuplicateHandle после создания потока, и используйте этот дескриптор в WaitForSingleObject.

1 голос
/ 08 июня 2009

Вы проверили, действительно ли дескриптор потока m_thread действителен?

Существуют обстоятельства, когда _beginthread вернет недопустимый дескриптор, особенно когда поток быстро завершает работу (что, безусловно, может иметь место в этом случае, поскольку поток может раскрутиться, пройти через ожидание (поскольку событие уже установлено) и затем завершиться ).

Вместо этого используйте _beginthreadex для создания дескриптора, хотя вам нужно будет вызвать _endthreadex, чтобы убедиться, что все вычищено.

1 голос
/ 08 июня 2009

вы можете рассмотреть возможность использования SignalObjectAndWait вместо отдельных вызовов SetEvent() и WaitForSingleObject(), так как это происходит как одна операция и сразу же завершится ошибкой, если событие не может быть передано.

0 голосов
/ 17 июня 2010

Хастуркун говорит, что SignalObjectAndWait является атомарной операцией.

Однако MSDN не согласен:

Обратите внимание, что "сигнал" и "ожидание" не гарантируется выполнение в качестве атомная операция. Потоки, выполняющиеся на другие процессоры могут наблюдать сигнализированное состояние первого объекта перед тем как вызывать поток SignalObjectAndWait начинает ждать второй объект.

Да, я немного запутался, и сейчас у меня болит голова, но я уверен, что я это выясню. Он может быть не атомарным, но, похоже, он говорит о том, что выполняет проверку того, что ваш поток ожидает объекта, прежде чем объект будет сигнализирован. Правильно?

0 голосов
/ 15 апреля 2010

Разве это не плохая практика - раздавать адрес объекта до того, как этот объект будет полностью построен. У нас есть контроль, когда новый поток выполнит obj->ThreadEntry(), это может быть после того, как конструктор завершил работу, есть полный объект для вызова ThreadEntry, или ThreadEntry может начаться до того, как будет создан объект.

0 голосов
/ 15 апреля 2010

Поток будет зависать, если SetEvent выполняется до WaitforSingleObject в потоке. Так что в этом случае WaitforSingleObject(m_event,INFINITE) будет ждать вечно.

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