进程与线程(四)线程中访问资源的同步
来源:互联网 发布:淘宝详情页750改950 编辑:程序博客网 时间:2024/05/12 09:42
一种方法就是使用关键段(Critical Section)进行全局变量的处理,关键段不宜过于复杂。
初始化的时候,建议使用InitializeCriticalSectionAndSpinCount而不单是InitializeCriticalSection,如果不使用旋转锁,当我们这个线程要访问的数据正在被其他线程处理时,将会被切换到等待状态,线程将从用户模式进入内核模式,这个过程中将浪费很多时间,也许在线程进入内核之前,资源已经被其他线程释放,所以我们加一个旋转锁处理。当然,在单核cpu下这种处理是毫无意义的,因为我们的线程陷入循环,某个正在占用资源的线程将没有机会处理和释放这个资源,这个不必我们多虑,在单核cpu中,InitializeCriticalSectionAndSpinCount的第二个参数dwSpinCount会被忽略,认为是0.
下面是个例子,当然如果只是这么一个简单的计算,我们完全没必要多线程,直接用等差数列的方程就可以解决,这么做反而会降低工作效率,这里只是一个例子。
所以下面这段代码中,不会有一个确定的打印结果
可以使用条件变量,使一个线程在资源没有更新的情况下进入睡眠,等待写入资源的线程来唤醒。
初始化的时候,建议使用InitializeCriticalSectionAndSpinCount而不单是InitializeCriticalSection,如果不使用旋转锁,当我们这个线程要访问的数据正在被其他线程处理时,将会被切换到等待状态,线程将从用户模式进入内核模式,这个过程中将浪费很多时间,也许在线程进入内核之前,资源已经被其他线程释放,所以我们加一个旋转锁处理。当然,在单核cpu下这种处理是毫无意义的,因为我们的线程陷入循环,某个正在占用资源的线程将没有机会处理和释放这个资源,这个不必我们多虑,在单核cpu中,InitializeCriticalSectionAndSpinCount的第二个参数dwSpinCount会被忽略,认为是0.
下面是个例子,当然如果只是这么一个简单的计算,我们完全没必要多线程,直接用等差数列的方程就可以解决,这么做反而会降低工作效率,这里只是一个例子。
1 DWORD g_num; 2 CRITICAL_SECTION cs; 3 4 // 唯一的应用程序对象 5 6 CWinApp theApp; 7 8 using namespace std; 9 10 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 11 { 12 _tsetlocale(LC_ALL,_T("chs") ); 13 ::system("title ReturnsMe的win32api测试程序"); 14 15 g_num = 0; 16 17 //初始化关键段和旋转锁 18 InitializeCriticalSectionAndSpinCount(&cs,4000); 19 20 //开启10线程,每个线程执行g_num累加, 21 HANDLE h[10]; 22 for (int i=0;i<10;i++) 23 { 24 h[i] = chBEGINTHREADEX(NULL,NULL,FuncThread,NULL,0,NULL); 25 } 26 27 WaitForMultipleObjects(10,h,TRUE,INFINITE); 28 29 //由于我们使用了同步处理,不出意外的话,应该打印出50500 30 wprintf(_T("num is %d \n"),g_num); 31 32 //打印完毕,我们也就不需要这个关键段了,应该删掉 33 DeleteCriticalSection(&cs); 34 35 system("pause"); 36 37 return 0; 38 } 39 DWORD WINAPI FuncThread(PVOID pvParam) 40 { 41 //进入关键段 42 EnterCriticalSection(&cs); 43 44 for (int i=0;i<=100;i++) 45 { 46 g_num = g_num + i; 47 } 48 49 //离开 50 LeaveCriticalSection(&cs); 51 52 return 0; 53 }另一种办法是使用SRWLock 在某些情况下,性能要比CS好一些,但功能却也有一些限制,特别注意的是,SRWLock允许多线程同时访问一个资源,但由于windows是抢占式操作系统,哪个线程在什么时候谁先谁后的访问一个资源是不确定的,所以我们也看不出什么时候同时访问了资源。
所以下面这段代码中,不会有一个确定的打印结果
1 DWORD g_num; 2 SRWLOCK srw_lock; 3 4 5 // 唯一的应用程序对象 6 7 CWinApp theApp; 8 9 using namespace std; 10 11 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 12 { 13 _tsetlocale(LC_ALL,_T("chs") ); 14 ::system("title ReturnsMe的win32api测试程序"); 15 16 g_num = 0; 17 18 //初始化一个锁,与CS不同,用完之后不用删除,因为系统会帮助我们做这些事情。 19 20 InitializeSRWLock(&srw_lock); 21 22 HANDLE hShared; 23 24 //开启10线程,每个线程执行g_num累加,在开启一个读取即时的g_num数值 25 HANDLE h[10],hh[10]; 26 for (int i=0,j=0;i<10;i++,j++) 27 { 28 h[i] = chBEGINTHREADEX(NULL,NULL,ExclusiveThread,NULL,0,NULL); 29 hh[j] = chBEGINTHREADEX(NULL,NULL,SharedThread,NULL,0,NULL); 30 } 31 32 33 WaitForMultipleObjects(10,h,TRUE,INFINITE); 34 WaitForMultipleObjects(10,hh,TRUE,INFINITE); 35 36 wprintf(_T("finally,g_num is %d \n"),g_num); 37 38 system("pause"); 39 40 return 0; 41 } 42 DWORD WINAPI ExclusiveThread(PVOID pvParam) 43 { 44 //写入资源,所以采用独占模式 45 AcquireSRWLockExclusive(&srw_lock); 46 47 for (int i=0;i<=100;i++) 48 { 49 g_num = g_num + i; 50 } 51 52 ReleaseSRWLockExclusive(&srw_lock); 53 54 return 0; 55 } 56 DWORD WINAPI SharedThread(PVOID pvParam) 57 { 58 //读取资源,共享模式 59 AcquireSRWLockShared(&srw_lock); 60 61 wprintf(_T("g_num is %d \n"),g_num); 62 63 ReleaseSRWLockShared(&srw_lock); 64 65 return 0; 66 }
可以使用条件变量,使一个线程在资源没有更新的情况下进入睡眠,等待写入资源的线程来唤醒。
1 DWORD g_num; 2 SRWLOCK srw_lock; 3 CONDITION_VARIABLE g_cv; 4 5 // 唯一的应用程序对象 6 7 CWinApp theApp; 8 9 using namespace std; 10 11 int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) 12 { 13 _tsetlocale(LC_ALL,_T("chs") ); 14 ::system("title ReturnsMe的win32api测试程序"); 15 16 g_num = 0; 17 18 //初始化一个锁 19 InitializeSRWLock(&srw_lock); 20 21 22 HANDLE h[2]; 23 24 25 h[1]= chBEGINTHREADEX(NULL,NULL,SharedThread,NULL,0,NULL); 26 h[0] = chBEGINTHREADEX(NULL,NULL,ExclusiveThread,NULL,0,NULL); 27 28 29 WaitForMultipleObjects(2,h,TRUE,INFINITE); 30 31 wprintf(_T("finally,g_num is %d \n"),g_num); 32 33 system("pause"); 34 35 return 0; 36 } 37 DWORD WINAPI ExclusiveThread(PVOID pvParam) 38 { 39 //写入资源,所以采用独占模式 40 AcquireSRWLockExclusive(&srw_lock); 41 42 for (int i=0;i<=100;i++) 43 { 44 g_num = g_num+ i; 45 } 46 47 Sleep(2000); 48 49 //线程进行太快效果不明显,这里睡眠2s后唤醒等待线程 50 51 WakeConditionVariable(&g_cv); 52 53 ReleaseSRWLockExclusive(&srw_lock); 54 55 return 0; 56 } 57 DWORD WINAPI SharedThread(PVOID pvParam) 58 { 59 //读取资源,采用共享模式 60 61 AcquireSRWLockShared(&srw_lock); 62 63 wprintf(_T("g_num is %d \n"),g_num); 64 65 wprintf(_T("waiting for the variable to be changed \n")); 66 67 //进入睡眠,第三个变量也分共享模式和独占模式,独占传入0,共享的情况如下所示。 68 69 SleepConditionVariableSRW(&g_cv,&srw_lock,INFINITE,CONDITION_VARIABLE_LOCKMODE_SHARED); 70 71 wprintf(_T("g_num has been changed, it's %d \n"),g_num); 72 73 ReleaseSRWLockShared(&srw_lock); 74 75 return 0; 76 }
- 进程与线程(四)线程中访问资源的同步
- C++ 操作系统进程中线程同步的四种方式
- 线程与进程的同步问题
- 进程与线程的同步机制
- 线程与进程共享的资源种类
- 线程(进程)的同步与互斥实例
- 同一进程中线程究竟享有线程的什么资源
- 进程,线程通信与同步
- 进程、线程通信与同步
- 进程线程同步与通信
- 进程与线程的通信与进程同步
- 在C++中实现四种进程或线程同步互斥的控制
- 在C++中实现四种进程或线程同步互斥的控制
- 线程与进程(中)
- 线程同步 资源锁定(四)Barrier类
- 四种线程或进程同步控制的方法
- 进程,线程,线程同步
- 四种进程线程同步机制
- xtree.js
- Android 完全退出程序方法
- log4j.rootLogger 与log4j.rootCategory 有什么区别 .
- required file `config.h.in' not found
- 进程与线程(三)进线程的优先级操作
- 进程与线程(四)线程中访问资源的同步
- android NDK 入门之在JNI中修改java中对象的成员变量的值
- Android 遍历界面控件
- framebuffer设备的参数
- String, inputstream 互换
- 思科企业路由器CISCO RV016
- linux 断开某个用户的终端连接
- qt中的字符串为什么前面要加tr
- Windows Phone网页体验版