C++多线程编程一 [关于数据竞争问题]
上一篇 / 下一篇 2012-07-03 08:40:56 / 个人分类:C++
采用多线程的好处大家都很熟悉了,可以充分利用系统资源,通过合理调度最大程序上并发执行,但是如果设计不当反而会与初衷相悖,带来更多的麻烦,本文主要就多线程编程中的“数据竞争”问题做一个归纳和总结,并给出WIN32下部分函数使用说明。51Testing软件测试网7{7g,A*@`:Qj
\]6`] oY)G0 多线程编程中数据竞争是一项关键的技术,常用的解决方法有以下四种:临界区、互斥量、 事件 、 信号量51Testing软件测试网8IA:hA(ay XQ`
51Testing软件测试网-|B"SR2o@*|q w0{:q临界区一般不推荐使用,下面主要介绍后面三种。51Testing软件测试网(F jAgh2q,wu5v
51Testing软件测试网&dvW]*|/p$s一、互斥量 Mutex51Testing软件测试网 Y0M4pfY6w
@^o^ x}9oA"|0 学过计算机网络的朋友相信对令牌环网应该不陌生,互斥量的作用就相当于一块令牌,每个主机都要竞争地去“申请”这张令牌,“获得”的主机才有权限在网上发数据包,而“令牌”只有一张,“令牌”的使用权只有当当前使用者“释放”后才能被其它主机“竞争申请”。
1W#E[| n!TwSumt+^0OW;}8GfJ0 互斥量的特点是只有一个,各线程竞争使用,一个线程获得后,在它释放前,其它线程只好等待。51Testing软件测试网?AkjR2q&M0E
J K"p6m`:[D9~D,Y N0 1、Win32平台下,互斥量为一个句柄,初始化方法如下:
vw ht t0 51Testing软件测试网"OKhD4Bw51Testing软件测试网a&XZ{2`V;C#|
i~jgk,s G?P~"f0Handle hMutex;51Testing软件测试网I7D \%w"AbUz`\7J 51Testing软件测试网7dV?H9M:}+?t x@hMutex = CreateMutex(NULL, TRUE, NULL); //创建后当前线程初始占有互斥量 ^4x8~O2o0 51Testing软件测试网Hg`:xp6ws7nReleaseMutex(hMutex); //创建后在主线程中释放互斥量从而子线程可以申请使用51Testing软件测试网+p%[ TJ3W~;X@!h.[.u uA XM#_6q4f_H?"o0hMutex = OpenMutex(MUTANT_ALL_ACCESS, TRUE, NULL); //打开互斥量,并声明子线程可以继承互斥量的句柄 T6x(C8].umE0 |
2、申请与释放
w&SM?5{@S0&Y#jW^(uW0U{A0
T-v7Ois(GGBX0WaitForSingleObject(hMutex, DWORD dwTimeOut); 2b\ PGE)I)i Q0 /* do the task; */ /mR;Lv!a*p~.K;~1{0 ReleaseMutex(hMutex); 3]h(v.fD#~3} f0 例如,可设超时为100毫秒,如下所示:51Testing软件测试网7z)U7[1X7Y;O aa v if (WAIT_TIMEOUT == WaitForSingleObject(hrecvEven, 100)) { 0F0\azr:Sn"i0 /* do something; */ }51Testing软件测试网6K JQ9V o-c/q2H else {51Testing软件测试网:i r[^O /* do the task; */ M Yp;x_w$`L$d0 ReleaseMutex(hMutex); } |
tK2jj |X6j0 二、事件 Event
zt l |t-aN3T0 51Testing软件测试网y,g-`)GY*][3l/l事件常被大家比喻成为一个“红绿灯”,可以在线程中方便地把灯设为“红”从而阻塞部分请求该资源的线程,或设为“绿”,开启所有因这部分资源而阻塞的线程。
#Dtf _(mai7@0 51Testing软件测试网|dG-|$\JjK最常用的一个场景就是网络缓冲区,当数据处理线程从网络缓冲区中提取数据包进行处理时,首先要做的操作就是判断缓冲区是否为空,如非空则提取并 处理,如为空则循环检测,这种实现会大大地把CPU资源浪费在循环检测,最好的方法是采用互斥事件,每次都用WaitForSingleObject去申 请资源,如果为“红”时则线程阻塞,而写入缓冲区线程将数据写入时执行SetEvent函数,从而在整个进程空间中广播“绿”灯,这样处理线程状况就可以 从阻塞变成就绪从而执行操作。
}M ['M7}:y"J\6J [0 51Testing软件测试网 E3].kU;].n Wk*X,pe在使用互斥事件时常犯的一个错误就是误把事件当做互斥量在两个线程中防止数据竞争,如下例所示:51Testing软件测试网u(iZ-Z N
51Testing软件测试网q1N;hK t51Testing软件测试网G rN$]A+N'`.e
Handle hEvent; 6TJE{(S0 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 实始化信号量,初始状态为非信号通知 1A!EgF[*bt GPG!p0 SetEvent(hEvent ); //信号通知 1O3{C}Bk0 ThreadA51Testing软件测试网;EsGy-`5g!e6xY { .y ]t%ALDj1T0 WaitForSingleObject(hEvent); 1y E7m3u ~0_w:P F;V wt0 ResetEvent(hEvent);51Testing软件测试网6_*Yn:D~6jK!} /* do the task; */ 2I k[N)s0 SetEvent(hEvnet); Zrg!z6_f'z/y0 } _!~n:|0q0 ThreadB51Testing软件测试网2fYaCl[&^ { VyP[B;Px0 WaitForSingleObject(hEvent);51Testing软件测试网/P _Lv*v_j9dJ ResetEvent(hEvent); U~{ G,wrV,LS&P)@0 /* do the task; */ .pJM `d0 SetEvent(hEvnet); |