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

本文探讨了在多线程环境下,通过封装条件变量和事件类来优化线程同步效率的方法。重点分析了如何避免在锁操作外调用线程条件函数,以及封装的CLConditionVariable和CLEvent类的实现原理。此外,通过实例演示了如何在不同线程间高效地唤醒和等待,从而显著提升系统响应性和资源利用。

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类似)
头文件:
ContractedBlock.gifExpandedBlockStart.gifView 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
实现:
ContractedBlock.gifExpandedBlockStart.gifView 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"
头文件:
ContractedBlock.gifExpandedBlockStart.gifView 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
实现:
ContractedBlock.gifExpandedBlockStart.gifView 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,使得其他等待该条件变量的线程能够继续等待,重新竞争。
测试:
ContractedBlock.gifExpandedBlockStart.gifView 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;
}


转载于:https://www.cnblogs.com/lq0729/archive/2011/10/22/2221185.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值