C++多线程编程一 [关于数据竞争问题]

上一篇 / 下一篇  2012-07-03 08:40:56 / 个人分类:C++

51Testing软件测试网zh/^(|R1v7p1g M'v(R

  采用多线程的好处大家都很熟悉了,可以充分利用系统资源,通过合理调度最大程序上并发执行,但是如果设计不当反而会与初衷相悖,带来更多的麻烦,本文主要就多线程编程中的“数据竞争”问题做一个归纳和总结,并给出WIN32下部分函数使用说明。51Testing软件测试网7{7g,A*@`:Qj

\]6`] oY)G0  多线程编程中数据竞争是一项关键的技术,常用的解决方法有以下四种:临界区、互斥量、 事件 、 信号量51Testing软件测试网8IA:hA(ay XQ`

51Testing软件测试网-|B"SR2o@*|q w0{:q

  临界区一般不推荐使用,下面主要介绍后面三种。51Testing软件测试网(F jA gh2q,wu5v

51Testing软件测试网&dvW]*|/p$s

  一、互斥量 Mutex51Testing软件测试网 Y0M4pfY6w

@^o^ x}9oA"|0  学过计算机网络的朋友相信对令牌环网应该不陌生,互斥量的作用就相当于一块令牌,每个主机都要竞争地去“申请”这张令牌,“获得”的主机才有权限在网上发数据包,而“令牌”只有一张,“令牌”的使用权只有当当前使用者“释放”后才能被其它主机“竞争申请”。

1W#E[| n!TwSumt+^0

OW;}8GfJ0  互斥量的特点是只有一个,各线程竞争使用,一个线程获得后,在它释放前,其它线程只好等待。51Testing软件测试网?AkjR2q&M0E

J K"p6m`:[D9~D,Y N0  1、Win32平台下,互斥量为一个句柄,初始化方法如下:

vw ht t0 51Testing软件测试网"OKhD4Bw

51Testing软件测试网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`:xp6ws7n

ReleaseMutex(hMutex); //创建后在主线程中释放互斥量从而子线程可以申请使用51Testing软件测试网+p%[ TJ3W~;X@!h.[.u

uAXM#_6q4f_H?"o0hMutex = OpenMutex(MUTANT_ALL_ACCESS, TRUE, NULL); //打开互斥量,并声明子线程可以继承互斥量的句柄

T6x(C8].um E0
51Testing软件测试网iUV4PQQ0u x

  2、申请与释放

w&SM ?5{@S0

&Y#jW^(uW0U{A0

T-v7Ois(GGBX0
WaitForSingleObject(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 JQ9Vo-c/q2H
       else  {51Testing软件测试网:i r[^O
              /* do the task; */  
M Yp;x_w$` L$d0              ReleaseMutex(hMutex); }

t K2jj |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 t

51Testing软件测试网G rN$]A+N'`.e

Handle hEvent;
6TJE{(S0      hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 实始化信号量,初始状态为非信号通知
1A!EgF[*bt G PG!p0     SetEvent(hEvent ); //信号通知
1O3{C}Bk0      ThreadA51Testing软件测试网;Es Gy-`5g!e6xY
      {
.y ]t%ALDj1T0           WaitForSingleObject(hEvent);
1yE7m3u ~0_w:P F;V wt0           ResetEvent(hEvent);51Testing软件测试网6_*Yn:D~6j K!}
           /* 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,w rV,LS&P)@0           /* do the task; */
.pJ M ` d0          SetEvent(hEvnet);
A)? XU9P _S0      }

.K+?!sP$nmu.@0  上例中运行时会如何意想不到的事情,线程A执行时明明申请到了互斥事件并把灯设为“红”,但线程B还是可以申请到互斥事件并执行,原因是这样 的,在A WaitForSingleObject成功后,在A执行ResetEvent之前,B可能抢占了CPU并执行了 WaitForSingleObject,从而B也有权利执行ResetEvent,这样A、B都有权执行,这种情况下,等于有两个人都可以控制“红绿 灯”从而导致“交通混乱”,最好的办法是在所有线程中只有一个线程可以开、关灯,或对互斥事件进行互斥量保护,防止数据竞争。

8|YX @l8D_([ r(H_~0 51Testing软件测试网H,~Pn8s2K"]Z&D9L^?

  三、信号量 Semaphore51Testing软件测试网(JitN ?1S@

(| K0I6y5?Kt\ zA0  信号量的意义可以理解为代表一种资源的个数,比如是排队系统中座位的数量,所有它的值是大于或等于1的,等于1时信号量则退化为互斥量 Mutex。51Testing软件测试网b_(R"s(G)Y3[+Yjm


TAG:

 

评分:0

我来说两句

Open Toolbar