void MiscThreadTestCase::TestThreadSuspend() { MyDetachedThread *thread = new MyDetachedThread(15, 'X'); CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Run() ); // this is for this demo only, in a real life program we'd use another // condition variable which would be signaled from wxThread::Entry() to // tell us that the thread really started running - but here just wait a // bit and hope that it will be enough (the problem is, of course, that // the thread might still not run when we call Pause() which will result // in an error) wxMilliSleep(300); for ( size_t n = 0; n < 3; n++ ) { thread->Pause(); if ( n > 0 ) { // don't sleep but resume immediately the first time wxMilliSleep(300); } CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, thread->Resume() ); } // wait until the thread terminates CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() ); }
wxCondError wxConditionInternal::Wait() { // increment the number of waiters { wxCriticalSectionLocker lock(m_csWaiters); m_numWaiters++; } m_mutex.Unlock(); // after unlocking the mutex other threads may Signal() us, but it is ok // now as we had already incremented m_numWaiters so Signal() will post the // semaphore and decrement m_numWaiters back even if it is called before we // start to Wait() const wxSemaError err = m_semaphore.Wait(); m_mutex.Lock(); if ( err == wxSEMA_NO_ERROR ) { // m_numWaiters was decremented by Signal() return wxCOND_NO_ERROR; } // but in case of an error we need to do it manually { wxCriticalSectionLocker lock(m_csWaiters); m_numWaiters--; } return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR; }
void wxThreadInternal::Pause() { // the state is set from the thread which pauses us first, this function // is called later so the state should have been already set wxCHECK_RET( m_state == STATE_PAUSED, wxT("thread must first be paused with wxThread::Pause().") ); // wait until the semaphore is Post()ed from Resume() m_semSuspend.Wait(); }
void MiscThreadTestCase::TestThreadConditions() { wxMutex mutex; wxCondition condition(mutex); // otherwise its difficult to understand which log messages pertain to // which condition //wxLogTrace(wxT("thread"), wxT("Local condition var is %08x, gs_cond = %08x"), // condition.GetId(), gs_cond.GetId()); // create and launch threads MyWaitingThread *threads[10]; size_t n; for ( n = 0; n < WXSIZEOF(threads); n++ ) { threads[n] = new MyWaitingThread( &mutex, &condition ); } for ( n = 0; n < WXSIZEOF(threads); n++ ) { CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() ); } // wait until all threads run // NOTE: main thread is waiting for the other threads to start size_t nRunning = 0; while ( nRunning < WXSIZEOF(threads) ) { CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() ); nRunning++; // note that main thread is already running } wxMilliSleep(500); #if 1 // now wake one of them up CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Signal() ); #endif wxMilliSleep(200); // wake all the (remaining) threads up, so that they can exit CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, condition.Broadcast() ); // give them time to terminate (dirty!) wxMilliSleep(500); }
void MiscThreadTestCase::TestDetached() { static const size_t nThreads = 3; MyDetachedThread *threads[nThreads]; size_t n; for ( n = 0; n < nThreads; n++ ) { threads[n] = new MyDetachedThread(10, 'A' + n); } threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY); threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY); for ( n = 0; n < nThreads; n++ ) { CPPUNIT_ASSERT_EQUAL( wxTHREAD_NO_ERROR, threads[n]->Run() ); } // wait until all threads terminate CPPUNIT_ASSERT_EQUAL( wxSEMA_NO_ERROR, gs_cond.Wait() ); }
wxCondError wxConditionInternal::Wait() { // increment the number of waiters IncrementAtomic( &m_numWaiters ); m_mutex.Unlock(); // a potential race condition can occur here // // after a thread increments nwaiters, and unlocks the mutex and before the // semaphore.Wait() is called, if another thread can cause a signal to be // generated // // this race condition is handled by using a semaphore and incrementing the // semaphore only if 'nwaiters' is greater that zero since the semaphore, // can 'remember' signals the race condition will not occur // wait ( if necessary ) and decrement semaphore wxSemaError err = m_semaphore.Wait(); m_mutex.Lock(); return err == wxSEMA_NO_ERROR ? wxCOND_NO_ERROR : wxCOND_MISC_ERROR; }