标签:
8.5 Slim读/写锁(SRWLock)——轻量级的读写锁
(1)SRWLock锁的目的
①允许读者线程同一时刻访问共享资源(因为不存在破坏数据的风险)
②写者线程应独占资源的访问权,任何其他线程(含写入的线程)要等这个写者线程访问完才能获得资源。
(2)SRWlock锁的使用方法
①初始化SRWLOCK结构体 InitializeSRWLock(PSRWLOCK pSRWLock);
②写者线程调用AcquireSRWLockExclusive(pSRWLock);以排它方式访问
读者线程调用AcquireSRWLockShared以共享方式访问
③访问完毕后,写者线程调用ReleaseSRWLockExclusive解锁。读者线程要调用ReleaseSRWLockShared解锁
④注意SRWLock不需要删除和销毁,所以不用Delete之类的,系统会自动清理。
(3)SRWLock与临界区的不同
①不存在TryEnter(Shared/Exclusive)SRWLock之类的函数;如果锁己经被占用,那么调用AcquireSRWLock(Shared/Exclusive)会阻塞调用线程。(如排它写入时锁会被独占)
②不能递归获得SRWLock,即一个线程不能为了多次写入资源而多次锁定资源,再多次调用ReleaseSRWLock*来释放锁。
【SRWLock程序】
#include <windows.h> #include <tchar.h> #include <locale.h> #include <time.h> ////////////////////////////////////////////////////////////////////////// const int g_iThreadCnt = 20; int g_iGlobalValue = 0; ////////////////////////////////////////////////////////////////////////// SRWLOCK g_sl = { 0 }; ////////////////////////////////////////////////////////////////////////// DWORD WINAPI ReadThread(PVOID pParam); DWORD WINAPI WriteThread(PVOID pParam); ////////////////////////////////////////////////////////////////////////// int _tmain() { _tsetlocale(LC_ALL, _T("chs")); srand((unsigned int)time(NULL)); //读写锁只需初始化,不需要手动释放,系统会自行处理 InitializeSRWLock(&g_sl); HANDLE aThread[g_iThreadCnt]; DWORD dwThreadId = 0; SYSTEM_INFO si = { 0 }; GetSystemInfo(&si); for (int i = 0; i < g_iThreadCnt;i++){ if (0 == rand()%2) aThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WriteThread, NULL, CREATE_SUSPENDED,&dwThreadId); else aThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReadThread, NULL, CREATE_SUSPENDED, &dwThreadId); SetThreadAffinityMask(aThread[i],1<<(i % si.dwNumberOfProcessors)); ResumeThread(aThread[i]); } //等待所有线程结束 WaitForMultipleObjects(g_iThreadCnt,aThread,TRUE,INFINITE); for (int i = 0; i < g_iThreadCnt;i++){ CloseHandle(aThread[i]); } _tsystem(_T("PAUSE")); return 0; } //////////////////////////////////////////////////////////////////////////// ////不加保护的读写 //DWORD WINAPI ReadThread(PVOID pParam) //{ // _tprintf(_T("Timestamp[%u]:Thread[ID:0x%x]读取全局变量值为%d\n"), // GetTickCount(),GetCurrentThreadId(),g_iGlobalValue); // return 0; //} // //////////////////////////////////////////////////////////////////////////// //DWORD WINAPI WriteThread(PVOID pParam) //{ // // for (int i = 0; i <= 4321; i++){ // g_iGlobalValue = i; // //模拟一个时间较长的处理过程 // for (int j = 0; j < 1000; j++); // } // // //我们的要求是写入的最后数值应该为4321,全局变量未被保护 // //其中线程可能读取0-4321的中间值,这不是我们想要的结果! // _tprintf(_T("Timestamp[%u]:Thread[ID:0x%x]写入数据值为%d\n"), // GetTickCount(), GetCurrentThreadId(), g_iGlobalValue); // return 0; //} ////////////////////////////////////////////////////////////////////////// DWORD WINAPI ReadThread(PVOID pParam) { //以共享的访问读 __try{ AcquireSRWLockShared(&g_sl); //读出来的全局变量要么是0,要么是4321。不可能有其他值 //当读线程第1个被调度时,会读到0.但一旦写线程被调度,以后所有的 //读取的值都会是4321 _tprintf(_T("Timestamp[%u]:Thread[ID:0x%X]读取全局变量值为%d\n"), GetTickCount(), GetCurrentThreadId(), g_iGlobalValue); } __finally{ ReleaseSRWLockShared(&g_sl); } return 0; } ////////////////////////////////////////////////////////////////////////// DWORD WINAPI WriteThread(PVOID pParam) { //写时以排它的方式 __try{ AcquireSRWLockExclusive(&g_sl); for (int i = 0; i <= 4321; i++){ g_iGlobalValue = i; SwitchToThread(); //故意切换到其他线程,很明显 //在这个循环的期间,因排它方式 //所以其它访问锁的线程会被挂起 //从而无法读或写。 } //我们的要求是写入的最后数值应该为4321,全局变量未被保护 //其中线程可能读取0-4321的中间值,这不是我们想要的结果! _tprintf(_T("Timestamp[%u]:Thread[ID:0x%X]写入数据值为%d\n"), GetTickCount(), GetCurrentThreadId(), g_iGlobalValue); } __finally{ ReleaseSRWLockExclusive(&g_sl); } return 0; }
(4)SRWLock锁与其他锁的比较
第8章 用户模式下的线程同步(3)_Slim读写锁(SRWLock)
标签:
原文地址:http://www.cnblogs.com/5iedu/p/4727734.html