Я пытаюсь запустить поток из ctor, поток должен спать, просыпаться, а затем выполнять дамп буфера, а затем снова спать, и так далее это код для ctor:

 Logger::Logger()
 {
   BufferInUse = &CyclicBuffer1;                        //buffer 1 will be used at    beggining
   MaxBufferSize = 5;                                   //initial state
   NumOfCycles = 0;
   CurrentMaxStringLength = 0;

   position = BufferInUse->end();
   OutPutMethod = odBuffer;                         //by default
   Thresh = 1;                                      //by default

   hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
   EventTime.QuadPart = -20000000;                          //1 second by default
   Mutex =  CreateMutex(NULL,FALSE,NULL);   
   if (Mutex == NULL) 
   { 
       OutputDebugStringA("CreateMutex error! the Logger will close \n");
       return ;
   }
   _beginthread( Logger::WorkerThread , 0,(void*)this );    //run the thread
}

Когда я отлаживаю его, требуется много времени для создания потока и завершения функции ctor, но за это время мои функции-члены объекта вызываются много раз (я вижу это при отладке). 1. Я хочу, чтобы поток создавался до вызова моих функций-членов, как лучше всего этого добиться?

Теперь моя реализация потока:

               void Logger::WorkerThread ( void *lpParam )
              {
                   Logger *log = static_cast <Logger*> (lpParam);
                   if (NULL == log->hTimer)
                   {
                      log->LogStringToOutput("CreateWaitableTimer() failed , Logger will close \n");
                       return;
                    }

               for(;;)
               {
                 //set timer for time specified by the EventTime variable inside the Logger
                 if (!SetWaitableTimer(log->hTimer, & (log->EventTime), 0, NULL, NULL, 0))
                 {
                     log->LogStringToOutput("SetWaitableTimer() failed , Logger will close\n" );
                    _endthread();
                 }

               //wait for timer
              if (WaitForSingleObject(log->hTimer, INFINITE) != WAIT_OBJECT_0)
              {
                   log->LogStringToOutput("WaitForSingleObject() failed! Logger will close\n");
                  _endthread();
                  return;
              }

              if(log->getOutputMethod() == odBuffer && log->BufferInUse->size() >= log->Thresh && !log->BufferInUse->empty())
              {
                  TTFW_LogRet ret;
                 ret = log->FullBufferDump();
                 if (ret != SUCCESS)
                 {
                       log->LogStringToOutput("Error occured in dumping cyclic buffer , the buffer will be cleared\n");
                 }
             }
           }

        }

Есть ли более элегантная реализация этой функциональности потока?

0
Dima Shifrin 13 Авг 2014 в 18:02
Вам действительно стоит использовать std::thread, std::mutex и std::this_thread.
 – 
Robert Allan Hennigan Leahy
13 Авг 2014 в 18:15
Я не могу, так как у меня только VS 2008 и нет лицензии на более новую версию, поэтому я не могу реализовать функции С ++ 11
 – 
Dima Shifrin
14 Авг 2014 в 09:54
C ++ 11 - это C ++. Вы отметили свой вопрос C ++, а не C ++ 03. Я добавил тег C ++ 03, чтобы прояснить, что вы не хотите или не можете использовать весь C ++.
 – 
Robert Allan Hennigan Leahy
14 Авг 2014 в 09:56

1 ответ

Лучший ответ

Вам нужен какой-то механизм для синхронного запуска WorkerThread и доступа к функциям-членам.

Например, используйте переменную условия (документы в msdn):

Добавить 3 участника в Logger:

class Logger{
...

private:        
    CRITICAL_SECTION CritSection;
    CONDITION_VARIABLE ConditionVar;
    bool WorkerThreadStarted;

...
};

А также

 Logger::Logger():WorkerThreadStarted(false)
 {
     EnterCriticalSection(&CritSection); //added

     BufferInUse = &CyclicBuffer1;    //buffer 1 will be used at    beggining

     ...
  }

 void Logger::WorkerThread ( void *lpParam )
 {

     WorkerThreadStarted=true; //added
     LeaveCriticalSection(&CritSection);

     Logger *log = static_cast <Logger*> (lpParam);
     if (NULL == log->hTimer)
     {
        log->LogStringToOutput("CreateWaitableTimer() failed , Logger will close \n");
         return;
     }


     ...
}

Добавить такую ​​функцию:

  void Logger::EnsureInitiallized(){

      EnterCriticalSection(&CritSection);

      // Wait until the predicate is TRUE

      while( !WorkerThreadStarted )
      {
         SleepConditionVariableCS(&ConditionVar, &CritSection, INFINITE);
      }

      LeaveCriticalSection(&CritSection);
  }

И для каждой записи функции-члена вызовите EnsureInitiallized ();

  void Logger::yourFunction(){
    EnsureInitiallized();

    ...
  }

Это пример, вы также можете использовать блокировку read_write, атомарное целое число и т. д.

1
byron he 14 Авг 2014 в 16:29
Это кажется разумным решением, но оно не работает, программа застревает на SleepConditionVariableCS (& ConditionVar, & CritSection, INFINITE); линия, и она остается такой навсегда
 – 
Dima Shifrin
14 Авг 2014 в 12:18
О, я допустил ошибку, в WorkerThread перед LeaveCriticalSection не следует вызывать функцию члена Logger, это вызовет самоблокировку. я исправил это выше.
 – 
byron he
14 Авг 2014 в 16:23
Это почти правда, WorkerThread является статической функцией, поэтому я передаю функции указатель на объект, чтобы я мог получить доступ к его членам, и если вы объявите члены как частные члены класса, вы не сможете получить к ним доступ, прежде чем получите указатель this, чтобы вы должен сначала выполнить приведение, а затем WorkerThreadStarted = true; // добавлен LeaveCriticalSection (& CritSection); или, может быть, объявить эти переменные как статические члены класса ...
 – 
Dima Shifrin
14 Авг 2014 в 16:46