多线程同步-条件变量
1.简介
当想入写入者线程和读取者线程以独占模式或共享模式访问同一个资源的时候,可以使用SRWLOCK读写锁。
- 如果读取者线程没有数据可读取,那么它应该将锁释放并等待,直到写入者线程产生了新的数据为止。
- 如果写入者线程产生的数据写满,那么写入者线程同样应该释放SRWLOCK并进入睡眠状态,直到读取者线程把数据清空为止。
windows通过SleepConditionVariableCS或SleepConditionVariableSRW函数,提供了一种条件变量。
BOOL SleepConditionVariableCS(
[in, out] PCONDITION_VARIABLE ConditionVariable,
[in, out] PCRITICAL_SECTION CriticalSection,
[in] DWORD dwMilliseconds
);
BOOL SleepConditionVariableSRW(
[in, out] PCONDITION_VARIABLE ConditionVariable,
[in, out] PSRWLOCK SRWLock,
[in] DWORD dwMilliseconds,
[in] ULONG Flags
);
- ConditionVariable:指向一个已初始化的条件变量。
- 参数2:指向一个关键段或者SRWLock指针。
- dwMilliseconds:表示希望线程花多少时间来等待条件变量被触发。
- Flags:指定一旦条件变量被触发,希望线程以何种方式来得到锁:对写入者线程来说,应该传入0,对读取者线程来说,传入CONDITION_VARIABLE_LOCKMODE_SHARED。
当指定的时间用完时候,如果条件变量未被触发,返回FALSE,否则返回TRUE。
当另一个线程检测到相应的条件已经满足的时候,比如有数据可读取了,它会调用下面的函数,阻塞在Sleep*函数中的线程会被唤醒。
WakeAllConditionVariable();
WakeConditionVariable();
2.示例
创建两个等待线程,一个苏醒线程,等待几秒后,sets线程,唤醒所有的别的线程。别的线程唤醒后执行结束退出。
// Interlocked.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <windows.h>
DWORD WINAPI sets(LPVOID);
DWORD WINAPI write(LPVOID);
BOOL RUNNING = FALSE;
SRWLOCK g_srwlock; //读写同步对象
CONDITION_VARIABLE g_con; //条件变量
int main()
{
HANDLE aThread[3];
DWORD ThreadID;
InitializeConditionVariable(&g_con);
InitializeSRWLock(&g_srwlock);
//创建多线程
aThread[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)write, NULL, 0, &ThreadID);
if (aThread[0] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
aThread[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)write, NULL, 0, &ThreadID);
if (aThread[0] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
aThread[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)sets, NULL, 0, &ThreadID);
if (aThread[0] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
WaitForMultipleObjects(3, aThread, TRUE, INFINITE);
// Close thread and mutex handles
for (int i = 0; i < 3; i++)
CloseHandle(aThread[i]);
return 0;
}
DWORD WINAPI write(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
AcquireSRWLockExclusive(&g_srwlock);
if (RUNNING == FALSE)
SleepConditionVariableSRW(&g_con, &g_srwlock, INFINITE, 0);
printf("write Thread %d finished...\n",
GetCurrentThreadId());
ReleaseSRWLockExclusive(&g_srwlock);
return 1;
}
DWORD WINAPI sets(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
AcquireSRWLockExclusive(&g_srwlock);
for (int i = 0; i < 100; ++i)
{
Sleep(50);
printf("sets Thread %d wait...\n", GetCurrentThreadId());
}
ReleaseSRWLockExclusive(&g_srwlock);
WakeAllConditionVariable(&g_con);
return 1;
}
执行结果: