Linux学习之"事件的封装(用条件变量互斥量实现Windows事件机制)"

POSIX.1说明:pthread_cond_broadcast等函数的调用无需考虑调用线程是否拥有锁,并建议在在lockunlock以外的区域调用。为什么?
§假设系统中有线程1和线程2:线程1获取mutex,在进行数据处理的时候,线程2(等待线程)也想获取mutex,但是此时被线程1所占用,线程2进入休眠,等待mutex被释。线程1做完数据处理后,调用pthread_cond_signal唤醒等待队列中某个线程,在本例中也就是线程2。线程1在调用pthread_mutex_unlock前,因为系统调度的原因,线程2获取使用CPU的权利,那么它就想要开始处理数据,但是在开始处理之前,mutex必须被获取,线程1正在使用mutex,所以线程2被迫再次进入休眠然后就是线程1执行pthread_mutex_unlock后,线程2方能被再次唤醒。 十分低效。
为什么要封装事件?
条件变量的处理比较复杂,需要有flag变量、固定的函数调用序列等等。
先看下封装的条件变量类“CLConditionVariable”(与CLMutex类似)
头文件:
View Code
#ifndef CLConditionVariable_H
#define CLConditionVariable_H

#include <pthread.h>
#include "CLStatus.h"

class CLMutex;

class CLConditionVariable
{
public:
/*
构造函数和析构函数出错时,会抛出字符串类型异常
*/
CLConditionVariable();
virtual ~CLConditionVariable();

CLStatus Wait(CLMutex *pMutex);
CLStatus Wakeup();
CLStatus WakeupAll();

private:
CLConditionVariable(const CLConditionVariable&);
CLConditionVariable& operator=(const CLConditionVariable&);

private:
pthread_cond_t m_ConditionVariable;
};

#endif
实现:
View Code
#include "CLConditionVariable.h"
#include "CLMutex.h"
#include "CLLog.h"

CLConditionVariable::CLConditionVariable()
{
int r = pthread_cond_init(&m_ConditionVariable, 0);
if(r != 0)
{
CLLog::WriteLogMsg("In CLConditionVariable::CLConditionVariable(), pthread_cond_init error", r);
throw "In CLConditionVariable::CLConditionVariable(), pthread_cond_init error";
}
}

CLConditionVariable::~CLConditionVariable()
{
int r = pthread_cond_destroy(&m_ConditionVariable);
if(r != 0)
{
CLLog::WriteLogMsg("In CLConditionVariable::~CLConditionVariable(), pthread_cond_destroy error", r);
throw "In CLConditionVariable::~CLConditionVariable(), pthread_cond_destroy error";
}
}

CLStatus CLConditionVariable::Wait(CLMutex *pMutex)
{
int r = pthread_cond_wait(&m_ConditionVariable, &(pMutex->m_Mutex));
if(r != 0)
{
CLLog::WriteLogMsg("In CLConditionVariable::Wait, pthread_cond_wait error", r);
return CLStatus(-1, 0);
}
else
{
return CLStatus(0, 0);
}
}

CLStatus CLConditionVariable::Wakeup()
{
int r = pthread_cond_signal(&m_ConditionVariable);
if(r != 0)
{
CLLog::WriteLogMsg("In CLConditionVariable::Wakeup, pthread_cond_signal error", r);
return CLStatus(-1, 0);
}
else
{
return CLStatus(0, 0);
}
}

CLStatus CLConditionVariable::WakeupAll()
{
int r = pthread_cond_broadcast(&m_ConditionVariable);
if(r != 0)
{
CLLog::WriteLogMsg("In CLConditionVariable::WakeupAll, pthread_cond_broadcast error", r);
return CLStatus(-1, 0);
}
else
{
return CLStatus(0, 0);
}
}
事件类"CLEvent"
头文件:
View Code
#ifndef CLEVENT_H
#define CLEVENT_H

#include "CLStatus.h"
#include "CLMutex.h"
#include "CLConditionVariable.h"

/*
创建一个初始无信号,自动重置信号的信号(用于唤醒一个 等待线程)
*/
class CLEvent
{
public:
/*
构造函数和析构函数出错时,会抛出字符串类型异常
*/
CLEvent( );
virtual ~CLEvent();

public:
CLStatus Set();

CLStatus Wait();

private:
CLEvent(const CLEvent&);
CLEvent& operator=(const CLEvent&);

private:
CLMutex m_Mutex;
CLConditionVariable m_Cond;
volatile int m_Flag;
};

#endif
实现:
View Code
#include "CLEvent.h"
#include "CLCriticalSection.h"
#include "CLLog.h"

CLEvent::CLEvent()
{
m_Flag = 0;
}

CLEvent::~CLEvent()
{
}

CLStatus CLEvent::Set()
{
try
{
CLCriticalSection cs(&m_Mutex);

m_Flag = 1;
}
catch(const char *str)
{
CLLog::WriteLogMsg("In CLEvent::Set(), exception arise", 0);
return CLStatus(-1, 0);
}

CLStatus s = m_Cond.Wakeup();
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLEvent::Set(), m_Cond.Wakeup error", 0);
return CLStatus(-1, 0);
}

return CLStatus(0, 0);
}

CLStatus CLEvent::Wait()
{
try
{
CLCriticalSection cs(&m_Mutex);

while(m_Flag == 0)
{
CLStatus s = m_Cond.Wait(&m_Mutex);
if(!s.IsSuccess())
{
CLLog::WriteLogMsg("In CLEvent::Wait(), m_Cond.Wait error", 0);
return CLStatus(-1, 0);
}
}

m_Flag = 0;
}
catch(const char* str)
{
CLLog::WriteLogMsg("In CLEvent::Wait(), exception arise", 0);
return CLStatus(-1, 0);
}

return CLStatus(0, 0);
}
注意:在Wait()中,当有等待条件变量的线程被唤醒后,在临界区范围内(解锁前)把m_Flag重新置0,使得其他等待该条件变量的线程能够继续等待,重新竞争。
测试:
View Code
#include <iostream>
#include <unistd.h>
#include "CLThread.h"
#include "CLExecutiveFunctionProvider.h"
#include "CLEvent.h"

using namespace std;

class CLMyFunction : public CLExecutiveFunctionProvider
{
public:
CLMyFunction()
{
}

virtual ~CLMyFunction()
{
}

virtual CLStatus RunExecutiveFunction(void *pContext)
{
CLEvent *pEvent = (CLEvent *)pContext;

//sleep(2);
pEvent->Set();

return CLStatus(0, 0);
}
};

int main()
{
CLEvent *pEvent = new CLEvent;

CLExecutiveFunctionProvider *myfunction = new CLMyFunction();
CLExecutive *pThread = new CLThread(myfunction);
pThread->Run((void *)pEvent);

pEvent->Wait();

pThread->WaitForDeath();

cout << "in main thread" << endl;

delete pThread;
delete myfunction;
delete pEvent;

return 0;
}


posted @ 2011-10-22 15:19  lq0729  阅读(1250)  评论(0编辑  收藏  举报