有时候负责数据读取的线程获得资源访问权后发现没有资源可以读取,或者写入线程在获得资源访问权的时候发现并没有数据可写或是当前的数据结构已满在等待处理的时候,我们希望线程可以释放掉锁,并进入睡眠状态,直到得到通知已经有数据可读或可写为止。这听起来确实很酷,因为无事可做的线程将不再占用(或占用很少的)cpu周期。
BOOL WINAPI SleepConditionVariableCS(
__inout PCONDITION_VARIABLE ConditionVariable,
__inout PCRITICAL_SECTION CriticalSection,
__in DWORD dwMilliseconds
);
BOOL WINAPI SleepConditionVariableSRW(
__inout PCONDITION_VARIABLE ConditionVariable,
__inout PSRWLOCK SRWLock,
__in DWORD dwMilliseconds,
__in ULONG Flags
);
这两个函数可以实现以上的功能。第一个参数是初始化的条件变量,调用的线程将等待这个条件变量。第二个条件为指向一个关键段或SRWLock的指针,指向已经初始化了的变量。第三个参数是等待的时间。SleepConditionVariableSRW可以指定得到锁的方式为独占或是共享,通过传入CONDITION_VARIABLE_LOCKMODE_SHARED表示以共享的方式获得锁,传入0表示以独占的方式获得锁。
VOID WINAPI WakeConditionVariable(
__inout PCONDITION_VARIABLE ConditionVariable
);
VOID WINAPI WakeAllConditionVariable(
__inout PCONDITION_VARIABLE ConditionVariable
);
这两个函数用来唤醒等待条件而睡眠的线程。WakeAllConditionVariable可以唤醒多个线程。
VOID WINAPI InitializeConditionVariable(
__out PCONDITION_VARIABLE ConditionVariable
);
这个函数初始化条件变量。
用一个简单的程序来说明整个流程。
写入线程代码:
DWORD WriteProc(LPVOID lp)
{
while(InterlockedCompareExchange(&bStop,1,1) != 1)
{
AcquireSRWLockExclusive(&srwLock);
if (ivec.size() == 10)//数组已经满了,睡眠等待读取线程的处理
{
SendDlgItemMessage(hMain,IDC_LIST_WRITE,LB_ADDSTRING,NULL,(LPARAM)L"写入线程--数组已满,等待。");
SleepConditionVariableSRW(&cvToWriteFile,&srwLock,INFINITE,0);
}
for (int i = 0;i < 10;++i)
{
int iNum = rand();
ivec.push_back(iNum);
}
//写文件
ofstream os(fileName.c_str());
copy(ivec.begin(),ivec.end(),ostream_iterator(os," "));
os.close();
SendDlgItemMessage(hMain,IDC_LIST_WRITE,LB_ADDSTRING,NULL,(LPARAM)L"写入线程--写文件完成。");
WakeConditionVariable(&cvToRead);//处理完成,唤醒读取线程
ReleaseSRWLockExclusive(&srwLock);
Sleep(100);
}
return 0;
}
读取线程代码:DWORD ReadProc(LPVOID lp)
{
while(InterlockedCompareExchange(&bStop,1,1) != 1)
{
AcquireSRWLockShared(&srwLock);
if (ivec.empty())//数组为空,睡眠等待写入数据
{
SendDlgItemMessage(hMain,IDC_LIST_READ,LB_ADDSTRING,NULL,(LPARAM)L"读取线程--数组为空,等待。");
SleepConditionVariableSRW(&cvToRead,&srwLock,INFINITE,CONDITION_VARIABLE_LOCKMODE_SHARED);
}
if (ivec.size() == 10)
{
for(;ivec.empty() == false;)
{
ivec.pop_back();
}
SendDlgItemMessage(hMain,IDC_LIST_READ,LB_ADDSTRING,NULL,(LPARAM)L"读取线程--清空数组完成。");
if(DeleteFileA(fileName.c_str()))
SendDlgItemMessage(hMain,IDC_LIST_READ,LB_ADDSTRING,NULL,(LPARAM)L"读取线程--删除文件完成。");
WakeConditionVariable(&cvToWriteFile);//操作完成,唤醒写入线程
}
ReleaseSRWLockShared(&srwLock);
Sleep(100);
}
return 0;
}
程序运行截图: