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

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

51Testing软件测试网!d4c'n)zM4\ E-MG8Z

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

y'z?R'v)w(jg0  多线程编程中数据竞争是一项关键的技术,常用的解决方法有以下四种:临界区、互斥量、 事件 、 信号量

'R6Vl xf^/Z7Spa)Ps0 51Testing软件测试网{8~:[Yq

  临界区一般不推荐使用,下面主要介绍后面三种。

p%Dm`q0P{yS0 51Testing软件测试网z![H @"vY

  一、互斥量 Mutex

5?R/s[%q,B:GD0OQ0

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

"LJrS0R F%q,^8OR0 51Testing软件测试网*Mf {)O.\0bO

  互斥量的特点是只有一个,各线程竞争使用,一个线程获得后,在它释放前,其它线程只好等待。51Testing软件测试网u BHK,Y9r

51Testing软件测试网o6cSBl?l f Bl$`)U$e

  1、Win32平台下,互斥量为一个句柄,初始化方法如下:

:Q*R0s/uj.\d_U0

6ixV\mo!k0 51Testing软件测试网 X g9R3@!M%P^:vG

51Testing软件测试网HLL)W5@1k6P

Handle hMutex;

lP8y1y|H9q)k0

6`4N4s&G@3I-F%h0hMutex = CreateMutex(NULL, TRUE, NULL); //创建后当前线程初始占有互斥量51Testing软件测试网kb&Z"Nnj

T5bufF0ReleaseMutex(hMutex); //创建后在主线程中释放互斥量从而子线程可以申请使用

'^;@%IIWd0 51Testing软件测试网G P"H/iI7z6v

hMutex = OpenMutex(MUTANT_ALL_ACCESS, TRUE, NULL); //打开互斥量,并声明子线程可以继承互斥量的句柄51Testing软件测试网 L@ ^ S$oI X

:x3U#p4SKU+c0  2、申请与释放

1bv_xy#n;L0 51Testing软件测试网 V d:UZ9yiD-p

W)G r]5sj0
WaitForSingleObject(hMutex, DWORD dwTimeOut);
([ ] X+B:G5I J0         /* do the task; */51Testing软件测试网6FK0Q;Wn6{ f(WEy
         ReleaseMutex(hMutex);51Testing软件测试网_V_~}IS
        例如,可设超时为100毫秒,如下所示:51Testing软件测试网a,D} skY
        if (WAIT_TIMEOUT == WaitForSingleObject(hrecvEven, 100))  {51Testing软件测试网)hv5k?:Po
              /* do something; */    }51Testing软件测试网RF]"n{:q o]o
       else  {51Testing软件测试网Xp xS^*B
              /* do the task; */   51Testing软件测试网2MQ+^m_%h
              ReleaseMutex(hMutex); }
51Testing软件测试网8iNL[k+{ ]c&N!n

  二、事件 Event51Testing软件测试网cqW{%v1A.`.U\^%W

'k^5Jd]#w Tt0  事件常被大家比喻成为一个“红绿灯”,可以在线程中方便地把灯设为“红”从而阻塞部分请求该资源的线程,或设为“绿”,开启所有因这部分资源而阻塞的线程。

8o gkK/p:{0

8F x0rw/B t0  最常用的一个场景就是网络缓冲区,当数据处理线程从网络缓冲区中提取数据包进行处理时,首先要做的操作就是判断缓冲区是否为空,如非空则提取并 处理,如为空则循环检测,这种实现会大大地把CPU资源浪费在循环检测,最好的方法是采用互斥事件,每次都用WaitForSingleObject去申 请资源,如果为“红”时则线程阻塞,而写入缓冲区线程将数据写入时执行SetEvent函数,从而在整个进程空间中广播“绿”灯,这样处理线程状况就可以 从阻塞变成就绪从而执行操作。

)vB~*q}a Y;W0 51Testing软件测试网1CA7e/P5E%T&of

  在使用互斥事件时常犯的一个错误就是误把事件当做互斥量在两个线程中防止数据竞争,如下例所示:51Testing软件测试网fT iASW

(rf,L+u4LP.u X0 51Testing软件测试网+k&Y U,v ?#K

Handle hEvent;
9T*OWnJ8t6n0      hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 实始化信号量,初始状态为非信号通知
o:^J,Rt.\7W0     SetEvent(hEvent ); //信号通知
-bk}2S3]KV0      ThreadA51Testing软件测试网1S*q%m+E2ps%JLm2X
      {
2sqFZ:O|p"?#gm0           WaitForSingleObject(hEvent);51Testing软件测试网.`~"I7D0WE
           ResetEvent(hEvent);
7a7p/Wn vx,?z7iv"w:_^0           /* do the task; */
F0} nC'ug OU D0          SetEvent(hEvnet);51Testing软件测试网r!e:QQ$P![%LKV
      }51Testing软件测试网4fMeA;`X+X
      ThreadB51Testing软件测试网&VD8o q} VB
      {51Testing软件测试网E.VB/h^ {z\*Fy
           WaitForSingleObject(hEvent);
(q"| ]^ LY0           ResetEvent(hEvent);
,t3Th"Z6G3d)RmV0           /* do the task; */
+a2is"{7RP6BS(Q cV$J0          SetEvent(hEvnet);51Testing软件测试网]-xcpw.B!]M0EnA
      }
51Testing软件测试网lW1f"fy"w

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

4_6}"[X(Tjt0  三、信号量 Semaphore

;HHrJ6F#V3f0

&PdY@&L1_r,j.w6[0  信号量的意义可以理解为代表一种资源的个数,比如是排队系统中座位的数量,所有它的值是大于或等于1的,等于1时信号量则退化为互斥量 Mutex。51Testing软件测试网7^/A1f;IN


TAG:

 

评分:0

我来说两句

Open Toolbar