Linux学习之"使条件变量互斥量避免无限等待"
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream>
#include <unistd.h>
#include "CLThread.h"
#include "CLExecutiveFunctionProvider.h"
#include "CLMutex.h"
#include "CLCriticalSection.h"
#include "CLConditionVariable.h"
using namespace std;
struct SPara
{
CLConditionVariable condition;
CLMutex mutex;
volatile int flag;
};
class CLMyFunction : public CLExecutiveFunctionProvider
{
public:
CLMyFunction()
{
}
virtual ~CLMyFunction()
{
}
virtual CLStatus RunExecutiveFunction(void *pContext)
{
SPara *p = (SPara *)pContext;
{
CLCriticalSection cs(&(p->mutex));
p->flag = 1;
}
p->condition.Wakeup();
return CLStatus(0, 0);
}
};
int main()
{
SPara *p = new SPara;
p->flag = 0;
CLExecutiveFunctionProvider *myfunction = new CLMyFunction();
CLExecutive *pThread = new CLThread(myfunction);
pThread->Run((void *)p);
{
CLCriticalSection cs(&(p->mutex));
while(p->flag == 0)
p->condition.Wait(&(p->mutex));
}
pThread->WaitForDeath();
cout << "in main thread" << endl;
delete pThread;
delete myfunction;
delete p;
return 0;
}
这个程序理想顺序是主线程先进入临界区,然后执行p->condition.Wait(&(p->mutex))释放互斥锁并在条件变量上等待;接着子线程进入临界区把flag置1,而后退出临界区,最后唤醒主线程,使其继续运行。
主线程中,临界区为从”CLCriticalSection cs(&(p->mutex))“开始,到主线程被挂起为止;子线程中,临界区为从“CLCriticalSection cs(&(p->mutex))”到p->flag被赋值为1结束。
当主线程先进入临界区时,此时主线程已经被挂起,而子线程的唤醒尚未执行,故不会产生无限等待。
当子线程先进入临界区时,此时p->flag被置1,而主线程对p->flag的判断尚未执行,故主线程不会再等待条件变量。
等待线程的执行顺序:
- 调用pthread_mutex_lock
- While(判断条件)pthread_cond_wait(while判断等待条件是由于线程可能不是被pthread_cond_signal唤醒,可能是由信号等唤醒(futex))
- 调用pthread_mutex_unlock
被等待线程
- 调用pthread_mutex_lock
- 修改条件
- 调用pthread_mutex_unlock
- 调用pthread_mutex_broadcast等