condition应用
condition源码
#ifndef _WIN32CONDITIONPRIVATEDATA_H_
#define _WIN32CONDITIONPRIVATEDATA_H_
#ifndef _WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#define InterlockedGet(x) InterlockedExchangeAdd(x,0)
namespace OpenThreads {
class Condition;
class Win32ConditionPrivateData {
public:
friend class Condition;
/// number of waiters.
long waiters_;
Win32ConditionPrivateData ()
{
waiters_ = 0;
sema_ = CreateSemaphore(NULL,0,0x7fffffff,NULL);
waiters_done_ = CreateEvent(NULL,FALSE,FALSE,NULL);
}
~Win32ConditionPrivateData ();
inline int broadcast ()
{
int have_waiters = 0;
long w = InterlockedGet(&waiters_);
if (w > 0)
{
// we are broadcasting.
was_broadcast_ = 1;
have_waiters = 1;
}
int result = 0;
if (have_waiters)
{
// Wake up all the waiters.
ReleaseSemaphore(sema_,waiters_,NULL);
WaitForSingleObject(waiters_done_,INFINITE) ;
//end of broadcasting
was_broadcast_ = 0;
}
return result;
}
inline int signal()
{
long w = InterlockedGet(&waiters_);
int have_waiters = w > 0;
int result = 0;
if (have_waiters)
{
if( !ReleaseSemaphore(sema_,1,NULL) )
result = -1;
}
return result;
}
inline int wait (Mutex& external_mutex, long timeout_ms)
{
// Prevent race conditions on the <waiters_> count.
InterlockedIncrement(&waiters_);
int result = 0;
external_mutex.unlock();
DWORD dwResult = WaitForSingleObject(sema_,timeout_ms);
if(dwResult != WAIT_OBJECT_0)
result = (int)dwResult;
// We're ready to return, so there's one less waiter.
InterlockedDecrement(&waiters_);
long w = InterlockedGet(&waiters_);
int last_waiter = was_broadcast_ && w == 0;
if (result != -1 && last_waiter)
SetEvent(waiters_done_);
external_mutex.lock();
return result;
}
protected:
/// Serialize access to the waiters count.
/// Mutex waiters_lock_;
/// Queue up threads waiting for the condition to become signaled.
HANDLE sema_;
/**
* An auto reset event used by the broadcast/signal thread to wait
* for the waiting thread(s) to wake up and get a chance at the
* semaphore.
*/
HANDLE waiters_done_;
/// Keeps track of whether we were broadcasting or just signaling.
size_t was_broadcast_;
};
#undef InterlockedGet
}
测试代码
#include <Windows.h> #include <OpenThreads/Thread.h> #include <OpenThreads/Mutex.h> #include <OpenThreads/Condition.h> #include <iostream> using namespace std; int g_number = 0; OpenThreads::Condition g_condition; OpenThreads::Mutex g_mutex; class A : public OpenThreads::Thread { void run() { while(1) { g_mutex.lock(); g_number++; g_mutex.unlock(); cout<<"A: number = "<<g_number<<endl; if (g_number >= 10) { g_condition.signal(); cout<<"A: signal"<<endl; return; } ::Sleep(10); } } }; class B : public OpenThreads::Thread { void run() { while(1) { g_mutex.lock(); g_number++; g_mutex.unlock(); cout<<"B: number = "<<g_number<<endl; if (g_number >= 10) { g_condition.signal(); cout<<"B: signal"<<endl; return; } ::Sleep(10); } } }; class C : public OpenThreads::Thread { void run() { g_mutex.lock(); cout<<"C: wait"<<endl; g_condition.wait(&g_mutex); cout<<"C: number = -1"<<endl; g_number = -1; g_mutex.unlock(); } }; int main() { A a; B b; C c; a.start(); b.start(); c.start(); a.join(); b.join(); c.join(); }
barrier为condition和mutex的应用,让线程可以同步等待运行
barrier源码
#ifndef _Win32BARRIERPRIVATEDATA_H_
#define _Win32BARRIERPRIVATEDATA_H_
#ifndef _WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <OpenThreads/Mutex.h>
#include <OpenThreads/Condition.h>
namespace OpenThreads {
class Barrier;
class Win32BarrierPrivateData {
friend class Barrier;
private:
Win32BarrierPrivateData() {};
~Win32BarrierPrivateData();
Condition cond; // cv for waiters at barrier
Mutex lock; // mutex for waiters at barrier
volatile int maxcnt; // number of threads to wait for
volatile int cnt; // number of waiting threads
volatile int phase; // flag to seperate two barriers
};
#include <OpenThreads/Barrier.h>
#include "Win32BarrierPrivateData.h"
using namespace OpenThreads;
// so compiler can place it somewhere
Win32BarrierPrivateData::~Win32BarrierPrivateData()
{
};
//----------------------------------------------------------------------------
//
// Decription: Constructor
//
// Use: public.
//
Barrier::Barrier(int numThreads) {
Win32BarrierPrivateData *pd = new Win32BarrierPrivateData();
pd->cnt = 0;
pd->phase = 0;
pd->maxcnt = numThreads;
_prvData = static_cast<void *>(pd);
}
//----------------------------------------------------------------------------
//
// Decription: Destructor
//
// Use: public.
//
Barrier::~Barrier() {
Win32BarrierPrivateData *pd =
static_cast<Win32BarrierPrivateData*>(_prvData);
delete pd;
}
//----------------------------------------------------------------------------
//
// Decription: Reset the barrier to its original state
//
// Use: public.
//
void Barrier::reset() {
Win32BarrierPrivateData *pd =
static_cast<Win32BarrierPrivateData*>(_prvData);
pd->cnt = 0;
pd->phase = 0;
}
//----------------------------------------------------------------------------
//
// Decription: Block until numThreads threads have entered the barrier.
//
// Use: public.
//
void Barrier::block(unsigned int numThreads) {
Win32BarrierPrivateData *pd =
static_cast<Win32BarrierPrivateData*>(_prvData);
if(numThreads != 0) pd->maxcnt = numThreads;
int my_phase;
pd->lock.lock();
my_phase = pd->phase;
++pd->cnt;
if (pd->cnt == pd->maxcnt) { // I am the last one
pd->cnt = 0; // reset for next use
pd->phase = 1 - my_phase; // toggle phase
pd->cond.broadcast();
}else{
while (pd->phase == my_phase) {
pd->cond.wait(&pd->lock);
}
}
pd->lock.unlock();
}