| 订阅 | 在线投稿
分享
 
 
 

Win32下两种用于C++的线程同步类(上)

2008-06-01 02:10:18 编辑來源:互联网 国际版 评论
 
 
本文为【Win32下两种用于C++的线程同步类(上)】的汉字拼音对照版显示拼音
  线xianchengtongbushiduo线xianchengchengxushejidegaixinneirongtademudeshizhengquechuliduo线xianchengbingfashidegezhongwentiliru线xianchengdedengdaiduoge线xiancheng访fangwentongyishujushidehuchifangsisuodengWin32tigongduozhongneigaiduixiangheshouduanyongyu线xianchengtongburuhuchiliangxinhaoliangshijianlinjiequdengsuobutongdeshihuchiliangxinhaoliangshijiandoushiWindowsdeneigaiduixiangdangchengxuduizhexieduixiangjinxingkongzhishihuizidongzhuanhuandaogaixintaierlinjiequbenshenbushineigaiduixiangtashigongzuozaiyonghutaidewomenzhidaocongyonghutaizhuanhuandaogaixintaishixuyaoyishijianweidaijiadesuoyijiarunengzaiyonghutaijiujiandanjiejuedewentijiukeyibubilaofangaixintaile

  zheliwoyaoshuodeshiliangzhongyongyuC++deduo线xianchengtongbuleitongguoduizheliangzhongleide使shiyongjiukeyifang便biandeshixianduibianlianghuodaimaduandejiasuokongzhicongerfangzhiduo线xianchengduibianliangbuzhengquedecaozuo

  suoweijiasuojiushishuodangwomenyao访fangwenmouyaohaibianliangzhiqiandouxuyaoshouxianhuodedayingcainengjixujiaruweihuodedayingzezhiyoudengdaiyigeyaohaibianliangyongyouyibasuoyige线xianchengbixuxiandedaozhebasuoqishichengweiyaoshikenenggengxingxiangcaikeyi访fangwenzhegebianliangerdangmougebianliangchiyouzhebasuodeshihouqita线xianchengjiubunengchongfudededaotazhiyoudengchiyousuode线xianchengbasuoguihuanyihouqita线xianchengcaiyoukenengdedaotazhisuoyizheyangzuojiushiweilefangzhiyige线xianchengduqumouduixiangtuzhonglingyi线xianchengduitajinxinglexiugaihuoliang线xianchengtongshiduiyibianliangjinxingxiugailiru

  // quanju

  strUCt MyStruct ... { int a, b; } ;

  MyStruct s;

  // 线xiancheng1

  int a = s.a;

  int b = s.b;

  // 线xiancheng2

  s.a ++ ;

  s.b -- ;

  jiarushijidezhixingshunxujiushishangshushuxiedeshunxunadaomeiyoushenmedanjiaru线xiancheng2dezhixingdaduanle线xiancheng1bianweiruxiashunxu

  int a = s.a; //线xiancheng1

  s.a++; //线xiancheng2

  s.b++; //线xiancheng2

  int b = s.b; //线xiancheng1

  namezheshi线xiancheng1duchulaideahebjiuhuiyouwentileyinweiashizaixiugaiqiandudeerbshizaixiugaihoududezheyangduchulaideshibuwanzhengdeshujuhuiduichengxudailaibukeyuliaodehouguotianzhidaolianggechengdetiaodushunxushishenmeyangdeweilefangzhizhezhongqingkuangdechuxianxuyaoduibianliangsjiasuoyejiushidang线xiancheng1dedaosuoyihoujiukeyifangxinde访fangwenszheshijiaru线xiancheng2yaoxiugaiszhiyoudeng线xiancheng1访fangwenwanchengyihoujiangsuoshifangcaikeyicongerbaozhengleshangshuliang线xianchengjiaocha访fangwenbianliangdeqingkuangbuhuichuxian

  使shiyongWin32tigongdelinjiequkeyifang便biandeshixianzhezhongsuo

  // quanju

  CRITICAL_SECTION cs;

  InitializeCriticalSection( & cs);

  // 线xiancheng1

  EnterCriticalSection( & cs);

  int a = s.a;

  int b = s.b;

  LeaveCriticalSection( & cs);

  // 线xiancheng2

  EnterCriticalSection( & cs);

  s.a ++ ;

  s.b -- ;

  LeaveCriticalSection( & cs);

  // zuihou

  DeleteCriticalSection( & cs);

  daimazhongdelinjiequbianliangcsjiukeyikanzuoshibianliangsdesuodanghanshuEnterCriticalSectionfanhuishidangqian线xianchengjiuhuodelezhebasuozhihoujiushiduibianliangde访fangwenle访fangwenwanchenghoutiaoyongLeaveCriticalSectionbiaoshishifangzhebasuodayingqita线xianchengjixu使shiyongta

  jiarumeidangxuyaoduiyigebianliangjinxingjiasuoshidouxuyaozuozhexiecaozuoxiandeyouxiemafanerqiebianliangcsyuszhiyouluojishangdesuoguanxizaiyufashangmeiyoushenmelianxizheduiyusuodezhilidailailebuxiaodemafanchengxuyuanzongshizuilandekeyixiangchugezhongtoulandebanfalaijiejuewentilirurangbeisuodebianliangyujiasuodebianliangxingchengwulishangdelianxi使shidesuobianliangchengweibeisuobianliangbukefengedeyibufenzhetingqilaishigehaozhuyi

  shouxianxiangdaodeshibasuofengbizaiyigeleilirangleidegouzaohanshuhexigouhanshulaizhiliduisuodechushihuahesuohuidongzuowomenchengzhegesuoweishilisuo

  class InstanceLockBase

  ... {

  CRITICAL_SECTION cs;

  protected :

  InstanceLockBase() ... { InitialCriticalSection( & cs); }

  ~ InstanceLockBase() ... { DeleteCriticalSection( & cs); }

  } ;

  jiarushuxiC++kandaozheliyidingzhidaohoumianwoyaoganshenmeleduilejiushijixuyinweiwobagouzaohanshuhexigouhanshudoushengmingweibaohudeprotectedzheyangweiyidezuoyongjiushizaizileili使shiyongtarangwomendebeibaohushujucongzhegeleijixunametamenbujiubukefengelema

  struct MyStruct: public InstanceLockBase

  ... { } ;

  shenmejiegoutihuannengcongleijixudangranC++zhongjiegoutiheleichulechengyuandemoren访fangwenkongzhibutongwaimeiyoushenmebuyiyangclassnengzuodestructyenengzuociwaiyexunihuanhuiwenjiarubeisuodeshigejiandanleixingbunengjixuzenmebannameyaomeyongyigeleiduizhegejiandanleixingjinxingfengzhuangjideJavaliyouintheIntegermayaomezhihaoshougongzhilitamendelianxilejiarubeisuoleiyijingyoulejileinemeiguanxiC++shidayingduojixudeduoyigejileiyemeishenme

  xianzaiwomendeshujulimianyijingbaohanyibasuolezhihoujiushiyaotianjiajiasuohejiesuodedongzuobatamenzuoweiInstanceLockBaseleidechengyuanhanshuzaiheshibuguole

  class InstanceLockBase

  ... {

  CRITICAL_SECTION cs;

  void Lock() ... { EnterCriticalSection( & cs); }

  void Unlock() ... { LeaveCriticalSection( & cs); }

  

  } ;

  kandaozhelikenenghuifaxianwobaLockheUnlockhanshudoushengmingweisiyoulenameruhe访fangwenzhelianggehanshuneshidewomenzongshixuyaoyouyigedifanglaitiaoyongzhelianggehanshuyishixianjiasuohejiesuodeerqietamenzongyinggaichengduichuxiandanC++yufabenshenmeinengxianzhiwomenbixuchengduidetiaoyonglianggehanshujiarujiawansuowanglejienahouguoshiyanchongdezheliyouyigeliwaijiushiC++duiyugouzaohanshuhexigouhanshudetiaoyongshizidongchengduideduilenajiubaduiLockheUnlockdetiaoyongzhuanmenxiezaiyigeleidegouzaohanshuhexigouhanshuzhong

  

  

  class InstanceLock

  ... {

  InstanceLockBase * _pObj;

  public :

  InstanceLock(InstanceLockBase * pObj)

  ... {

  _pObj = pObj; // zhelihuibaocunyifenzhixiangsdezhizhenyongyujiesuo

  if (NULL != _pObj)

  _pObj -> Lock(); // zhelijiasuo

  }

  ~ InstanceLock()

  ... {

  if (NULL != _pObj)

  _pObj -> Unlock(); // zhelijiesuo

  }

  } ;

  zuihoubiewanglezaileiInstanceLockBasezhongbaInstanceLockshengmingweiyouyuan使shidetanengzhengque访fangwenLockheUnlockzhelianggesiyouhanshu

  class InstanceLockBase

  ... {

  friend class InstanceLock;

  

  } ;

  haoleyouleshangmiandejichuxianzaiduibianliangsdejiajiesuozhilibianchengleduiInstanceLockdeshilideshengmingzhouqidezhililejiaruwomenyouyigehanshuModifySzhongyaoduisjinxingxiugainamezhiyaozaihanshuyikaishijiushengmingyigeInstaceLockdeshilizheyangzhenggehanshujiuzidongduisjiasuoyidanjinruzhegehanshuqita线xianchengjiudoubunenghuodesdesuole

  void ModifyS()

  ... {

  InstanceLock lock ( & s); // zheliyijingshixianjiasuole

  // some operations on s

  } // yidanlikailockduixiangdezuoyongyuzidongjiesuo

  jiarushiyaoduimouhanshuzhongyibufendaimajiasuozhiyaoyongyiduidakuohaobatamenkuoqilaizaishengmingyigelockjiukeyile

  

  ... {

  InstanceLock lock ( & s);

  // do something

  }

  

  haolejiushizhemejiandanxiamianlaikanyigeceshi

  shouxianyubeiyigeshuchuhanshuduiwomenlijiechengxuyoubangzhutahuizaishuchuwomenxiangshuchudeneirongtongshidachuxinghaoheshijian

  void Say( char * text)

  ... {

  static int count = 0 ;

  SYSTEMTIME st;

  ::GetLocalTime( & st);

  printf( " %03d [%02d:%02d:%02d.%03d]%s " , ++ count, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, text);

  }

  dangranyuanzeshangdangduo线xianchengdoutiaoyongzhegehanshushiyinggaiduiqijingtaijububianliangcountjinxingjiasuozhelijiushengluele

  womenshengmingyigefeichangjiandandebeisuodeleixingbingshengchengyigeshili

  class MyClass: public InstanceLockBase

  ... {} ;

  MyClass mc;

  zi线xianchengderenwujiushiduizhegeduixiangjiasuoranhoushuchuyixiexinxi

  DWord CALLBACK ThreadProc(LPVOID param)

  ... {

  InstanceLock il( & mc);

  Say( " in sub thread, lock " );

  Sleep( 2000 );

  Say( " in sub thread, unlock " );

  return 0 ;

  }

  zhelihuishuchuliangtiaoxinxiyishizaigangganghuodesuodeshijianershizaishifangsuodeshihouzhongjiantongguoSleeplaiyanchi2miao

  zhu线xianchengfuzekaiqizi线xianchengranhouyeduimcjiasuo

  CreateThread( 0 , 0 , ThreadProc, 0 , 0 , 0 );

  ... {

  InstanceLock il( & mc);

  Say( " in main thread, lock " );

  Sleep( 3000 );

  Say( " in main thread, lock " );

  }

  yunxingcichengxudedaodeshuchuruxia

  001 [13:43:23.781]in main thread, lock

  002 [13:43:26.781]in main thread, lock

  003 [13:43:26.781]in sub thread, lock

  004 [13:43:28.781]in sub thread, unlock

  congqishuchudexinghaoheshijiankeyiqingchudekandaoliangge线xianchengjiandehuchidangzhu线xianchengqiahaoshouxianhuodesuoshitahuiyanchi3miaoranhoushifangsuozhihouzi线xianchengcaideyijixujinxingzhegeliziyezhengshiwomendeleigongzuodehenhao

  zongjieyixiayao使shiyongInstanceLockxilieleiyaozuodejiushi

  1rangbeisuoleicongInstanceLockBasejixu

  2suoyouyao访fangwenbeisuoduixiangdedaimaqianmianshengmingInstanceLockdeshilibingchuanrubeisuoduixiangdezhizhen

  fuwanzhengyuandaima

  #pragma once

  #include < windows.h >

  class InstanceLock;

  class InstanceLockBase

  ... {

  friend class InstanceLock;

  CRITICAL_SECTION cs;

  void Lock()

  ... {

  ::EnterCriticalSection( & cs);

  }

  void Unlock()

  ... {

  ::LeaveCriticalSection( & cs);

  }

  protected :

  InstanceLockBase()

  ... {

  ::InitializeCriticalSection( & cs);

  }

  ~ InstanceLockBase()

  ... {

  ::DeleteCriticalSection( & cs);

  }

  } ;

  

   class InstanceLock

  ... {

  InstanceLockBase * _pObj;

  public :

  InstanceLock(InstanceLockBase * pObj)

  ... {

  _pObj = pObj;

  if (NULL != _pObj)

  _pObj -> Lock();

  }

  ~ InstanceLock()

  ... {

  if (NULL != _pObj)

  _pObj -> Unlock();

  }

  } ;原文
 
 
线程同步是多线程程序设计的核心内容,它的目的是正确处理多线程并发时的各种问题,例如线程的等待、多个线程访问同一数据时的互斥,防死锁等。Win32提供多种内核对象和手段用于线程同步,如互斥量、信号量、事件、临界区等。所不同的是,互斥量、信号量、事件都是Windows的内核对象,当程序对这些对象进行控制时会自动转换到核心态,而临界区本身不是内核对象,它是工作在用户态的。我们知道从用户态转换到核心态是需要以时间为代价的,所以假如能在用户态就简单解决的问题,就可以不必劳烦核心态了。   这里我要说的是两种用于C++的多线程同步类,通过对这两种类的使用就可以方便的实现对变量或代码段的加锁控制,从而防止多线程对变量不正确的操作。   所谓加锁,就是说当我们要访问某要害变量之前,都需要首先获得答应才能继续,假如未获得答应则只有等待。一个要害变量拥有一把锁,一个线程必须先得到这把锁(其实称为钥匙可能更形象)才可以访问这个变量,而当某个变量持有这把锁的时候,其他线程就不能重复的得到它,只有等持有锁的线程把锁归还以后其他线程才有可能得到它。之所以这样做,就是为了防止一个线程读取某对象途中另一线程对它进行了修改,或两线程同时对一变量进行修改,例如: // 全局: strUCt MyStruct ... { int a, b; } ; MyStruct s; // 线程1: int a = s.a; int b = s.b; // 线程2: s.a ++ ; s.b -- ;   假如实际的执行顺序就是上述书写的顺序那到没有什么,但假如线程2的执行打断了线程1,变为如下顺序: int a = s.a; //线程1 s.a++; //线程2 s.b++; //线程2 int b = s.b; //线程1   那么这时线程1读出来的a和b就会有问题了,因为a是在修改前读的,而b是在修改后读的,这样读出来的是不完整的数据,会对程序带来不可预料的后果。天知道两个程的调度顺序是什么样的。为了防止这种情况的出现,需要对变量s加锁,也就是当线程1得到锁以后就可以放心的访问s,这时假如线程2要修改s,只有等线程1访问完成以后将锁释放才可以,从而保证了上述两线程交叉访问变量的情况不会出现。   使用Win32提供的临界区可以方便的实现这种锁: // 全局: CRITICAL_SECTION cs; InitializeCriticalSection( & cs); // 线程1: EnterCriticalSection( & cs); int a = s.a; int b = s.b; LeaveCriticalSection( & cs); // 线程2: EnterCriticalSection( & cs); s.a ++ ; s.b -- ; LeaveCriticalSection( & cs); // 最后: DeleteCriticalSection( & cs);   代码中的临界区变量(cs)就可以看作是变量s的锁,当函数EnterCriticalSection返回时,当前线程就获得了这把锁,之后就是对变量的访问了。访问完成后,调用LeaveCriticalSection表示释放这把锁,答应其他线程继续使用它。   假如每当需要对一个变量进行加锁时都需要做这些操作,显得有些麻烦,而且变量cs与s只有逻辑上的锁关系,在语法上没有什么联系,这对于锁的治理带来了不小的麻烦。程序员总是最懒的,可以想出各种偷懒的办法来解决问题,例如让被锁的变量与加锁的变量形成物理上的联系,使得锁变量成为被锁变量不可分割的一部分,这听起来是个好主意。   首先想到的是把锁封闭在一个类里,让类的构造函数和析构函数来治理对锁的初始化和锁毁动作,我们称这个锁为“实例锁”: class InstanceLockBase ... { CRITICAL_SECTION cs; protected : InstanceLockBase() ... { InitialCriticalSection( & cs); } ~ InstanceLockBase() ... { DeleteCriticalSection( & cs); } } ;   假如熟悉C++,看到这里一定知道后面我要干什么了,对了,就是继续,因为我把构造函数和析构函数都声明为保护的(protected),这样唯一的作用就是在子类里使用它。让我们的被保护数据从这个类继续,那么它们不就不可分割了吗: struct MyStruct: public InstanceLockBase ... { … } ;   什么?结构体还能从类继续?当然,C++中结构体和类除了成员的默认访问控制不同外没有什么不一样,class能做的struct也能做。此外,也许你还会问,假如被锁的是个简单类型,不能继续怎么办,那么要么用一个类对这个简单类型进行封装(记得Java里有int和Integer吗),要么只好手工治理它们的联系了。假如被锁类已经有了基类呢?没关系,C++是答应多继续的,多一个基类也没什么。   现在我们的数据里面已经包含一把锁了,之后就是要添加加锁和解锁的动作,把它们作为InstanceLockBase类的成员函数再合适不过了: class InstanceLockBase ... {  CRITICAL_SECTION cs;  void Lock() ... { EnterCriticalSection( & cs); }  void Unlock() ... { LeaveCriticalSection( & cs); }  … } ;   看到这里可能会发现,我把Lock和Unlock函数都声明为私有了,那么如何访问这两个函数呢?是的,我们总是需要有一个地方来调用这两个函数以实现加锁和解锁的,而且它们总应该成对出现,但C++语法本身没能限制我们必须成对的调用两个函数,假如加完锁忘了解,那后果是严重的。这里有一个例外,就是C++对于构造函数和析构函数的调用是自动成对的,对了,那就把对Lock和Unlock的调用专门写在一个类的构造函数和析构函数中: class InstanceLock ... {  InstanceLockBase * _pObj;  public :   InstanceLock(InstanceLockBase * pObj)   ... {    _pObj = pObj; // 这里会保存一份指向s的指针,用于解锁    if (NULL != _pObj)    _pObj -> Lock(); // 这里加锁   }   ~ InstanceLock()   ... {    if (NULL != _pObj)    _pObj -> Unlock(); // 这里解锁  } } ;   最后别忘了在类InstanceLockBase中把InstanceLock声明为友元,使得它能正确访问Lock和Unlock这两个私有函数: class InstanceLockBase ... {  friend class InstanceLock;  … } ;   好了,有了上面的基础,现在对变量s的加解锁治理变成了对InstanceLock的实例的生命周期的治理了。假如我们有一个函数ModifyS中要对s进行修改,那么只要在函数一开始就声明一个InstaceLock的实例,这样整个函数就自动对s加锁,一旦进入这个函数,其他线程就都不能获得s的锁了: void ModifyS() ... {  InstanceLock lock ( & s); // 这里已经实现加锁了  // some operations on s } // 一旦离开lock对象的作用域,自动解锁   假如是要对某函数中一部分代码加锁,只要用一对大括号把它们括起来再声明一个lock就可以了: … ... {  InstanceLock lock ( & s);  // do something … } …   好了,就是这么简单。下面来看一个测试。   首先预备一个输出函数,对我们理解程序有帮助。它会在输出我们想输出的内容同时打出行号和时间: void Say( char * text) ... {  static int count = 0 ;  SYSTEMTIME st;  ::GetLocalTime( & st);  printf( " %03d [%02d:%02d:%02d.%03d]%s " , ++ count, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, text); }   当然,原则上当多线程都调用这个函数时应该对其静态局部变量count进行加锁,这里就省略了。   我们声明一个非常简单的被锁的类型,并生成一个实例: class MyClass: public InstanceLockBase ... {} ; MyClass mc;   子线程的任务就是对这个对象加锁,然后输出一些信息: DWord CALLBACK ThreadProc(LPVOID param) ... {  InstanceLock il( & mc);  Say( " in sub thread, lock " );  Sleep( 2000 );  Say( " in sub thread, unlock " );  return 0 ; }   这里会输出两条信息,一是在刚刚获得锁的时间,二是在释放锁的时候,中间通过Sleep来延迟2秒。   主线程负责开启子线程,然后也对mc加锁: CreateThread( 0 , 0 , ThreadProc, 0 , 0 , 0 ); ... {  InstanceLock il( & mc);  Say( " in main thread, lock " );  Sleep( 3000 );  Say( " in main thread, lock " ); }   运行此程序,得到的输出如下: 001 [13:43:23.781]in main thread, lock 002 [13:43:26.781]in main thread, lock 003 [13:43:26.781]in sub thread, lock 004 [13:43:28.781]in sub thread, unlock   从其输出的行号和时间可以清楚的看到两个线程间的互斥:当主线程恰好首先获得锁时,它会延迟3秒,然后释放锁,之后子线程才得以继续进行。这个例子也证实我们的类工作的很好。   总结一下,要使用InstanceLock系列类,要做的就是:   1、让被锁类从InstanceLockBase继续   2、所有要访问被锁对象的代码前面声明InstanceLock的实例,并传入被锁对象的指针。   附:完整源代码: #pragma once #include < windows.h > class InstanceLock; class InstanceLockBase ... {  friend class InstanceLock;  CRITICAL_SECTION cs;  void Lock()  ... {   ::EnterCriticalSection( & cs);  }  void Unlock()  ... {   ::LeaveCriticalSection( & cs);  }  protected :  InstanceLockBase()  ... {   ::InitializeCriticalSection( & cs);  }  ~ InstanceLockBase()  ... {   ::DeleteCriticalSection( & cs);  } } ; class InstanceLock ... {  InstanceLockBase * _pObj;  public :   InstanceLock(InstanceLockBase * pObj)   ... {    _pObj = pObj;    if (NULL != _pObj)     _pObj -> Lock();   }  ~ InstanceLock()  ... {   if (NULL != _pObj)    _pObj -> Unlock();  } } ;
󰈣󰈤
日版宠物情人插曲《Winding Road》歌词

日版宠物情人2017的插曲,很带节奏感,日语的,女生唱的。 最后听见是在第8集的时候女主手割伤了,然后男主用嘴帮她吸了一下,插曲就出来了。 歌手:Def...

兄弟共妻,我成了他们夜里的美食

老钟家的两个儿子很特别,就是跟其他的人不太一样,魔一般的执着。兄弟俩都到了要结婚的年龄了,不管自家老爹怎么磨破嘴皮子,兄弟俩说不娶就不娶,老父母为兄弟两操碎了心...

网络安全治理:国家安全保障的主要方向是打击犯罪,而不是处置和惩罚受害者

来源:中国青年报 新的攻击方法不断涌现,黑客几乎永远占据网络攻击的上风,我们不可能通过技术手段杜绝网络攻击。国家安全保障的主要方向是打击犯罪,而不是处置和惩罚...

 
 
 
>>返回首页<<
 为你推荐
 
 
 
 转载本文
 UBB代码 HTML代码
复制到剪贴板...
 
 
 热帖排行
 
清淡自然的清纯模特
倩女幽魂_美丽女生
[i]黄山
雪棉
 
 
王朝网络微信公众号
微信扫码关注本站公众号wangchaonetcn
 
  免责声明:本文仅代表作者个人观点,与王朝网络无关。王朝网络登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
©2005- 王朝网络 版权所有