线程同步之读写锁(锁操作的补充)
轻量级的读写锁(Slim Reader-Writer locks):读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。
这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。
写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。
读写锁比起mutex具有更高的适用性,具有更高的并行性,可以有多个线程同时占用读模式的读写锁,但是只能有一个线程占用写模式的读写锁,读写锁的三种状态:
1.当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞
2.当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是以写模式对它进行加锁的线程将会被阻塞
3.当读写锁在读模式的锁状态时,如果有另外的线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁的请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求则长期阻塞。
SRW代表-------Slim Reader-Writer
函数解析:
1.// 初始化读写锁
VOID WINAPI InitializeSRWLock
(
__out PSRWLOCK SRWLock
);
函数功能:初始化读写锁
2.// 独占式访问
VOID WINAPI AcquireSRWLockExclusive
(
__inout PSRWLOCK SRWLock
);
函数功能:写入者线程申请写资源。
3.// 独占式释放
VOID WINAPI ReleaseSRWLockExclusive
(
__inout PSRWLOCK SRWLock
);
函数功能:写入者线程写资源完毕,释放对资源的占用。
4.// 共享式访问
VOID WINAPI AcquireSRWLockShared
(
__inout PSRWLOCK SRWLock
);
函数功能:读取者线程申请读资源。
5.// 共享式释放
VOID WINAPI ReleaseSRWLockShared
(
__inout PSRWLOCK SRWLock
);
函数功能:读取者线程结束读取资源,释放对资源的占用。
注意点:
1.访问方式只能选择其一,不可以同时使用。即一个线程仅能锁定资源一次,不能多次锁定资源。
2.读写锁声明后要初始化,但不用销毁,系统会自动清理读写锁。
3.读取者和写入者分别调用不同的申请函数和释放函数。
区别:
1.AcquireSRWLockExclusive抢占式的,当线程上锁后,其他线程无法进行访问。直到 ReleaseSRWLockExclusive,释放后。一般用于写操作。
2.AcquireSRWLockShared 是共享式的,即使线程上锁后,其他线程也可以进行再次访问。一般用于读操作。
源代码: // Semaphore.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Windows.h> #include <process.h> //线程数 #define g_nThreadNum 3 //信号量 SRWLOCK g_srwLock; //累加数 int g_nCount = 50; unsigned _stdcall WriteThread(void * lParam) { // 独占式访问 AcquireSRWLockExclusive(&g_srwLock); g_nCount++; // 独占式释放 ReleaseSRWLockExclusive(&g_srwLock); return 0; } unsigned _stdcall ReadThread(void *lParam) { // 共享式访问 AcquireSRWLockShared(&g_srwLock); printf("g_nCount=%d\n", g_nCount); // 共享式释放 ReleaseSRWLockShared(&g_srwLock); return 0; } int _tmain(int argc, _TCHAR* argv[]) { //// 初始化读写锁 InitializeSRWLock(&g_srwLock); //启动线程 HANDLE pThread[g_nThreadNum]; pThread[0] = (HANDLE)_beginthreadex(NULL, 0, ReadThread, NULL, 0, 0); pThread[1] = (HANDLE)_beginthreadex(NULL, 0, WriteThread, NULL, 0, 0); pThread[2] = (HANDLE)_beginthreadex(NULL, 0, ReadThread, NULL, 0, 0); //等待线程结束 WaitForMultipleObjects(g_nThreadNum, pThread, TRUE, INFINITE); printf("g_nCount:%d\n", g_nCount); //释放资源 for (int i = 0; i < g_nThreadNum; ++i) { CloseHandle(pThread[i]); } getchar(); return 0; }