当前位置: 首页 > news >正文

C++语言编程规范-并发

01  

规则 10.1 多线程、进程并行访问共享资源时,一定要加锁保护

说明:共享资源包括全局变量,静态变量,共享内存,文件等。建议封装像智能指针一样的对象对锁进行管理,比如我们就封装了一个 auto_lock,在构造时申请锁,析构中释放锁,保证不会忘记“解锁”。如果锁的作用范围有限,则可以这样:

    do  {  auto_lock lock(&lock);  //....  }while(0);

    02  

    规则 10.2 锁的职责单一

    说明:每个锁只锁一个唯一共享资源;这样,才能保证锁应用的单一,也能更好的确保加锁的范围尽量小。

    对于共享全局资源,应该根据实际需要,每类或每个资源,有一把锁。这样,这把锁只锁对这个资源访问的代码,通常这样的代码都会是比较简单的资源操作代码,不会是复杂的函数调用等。相反,如果我们对几类

    或几个资源共用一把锁。这把锁的责任范围就大了,使用复杂,很难理清锁之间的关系(有没有释放锁,或者锁之间的嵌套加锁等),容易导致死锁问题。

    规则 10.3 锁范围尽量小,只锁对应资源操作代码

    说明:使用锁时,尽量减少锁的使用范围。我们使用锁,为了方便,会大范围的加锁,如:直接锁几个函数调用。这种使用,一方面会导致多线程执行效率的低下,容易变成串行执行;另一方面,容易出现锁未

    释放,或者锁的代码中再加锁的场景,最后导致死锁。所以,对锁操作的最好办法,就是只锁简单资源操作代码。对应资源访问完后,马上释放锁。尽量在函数内部靠近资源操作的地方加锁而不是靠近线程、函数外部加锁。

    03  

    规则 10.4 避免嵌套加锁;如果必须加锁,务必保证不同地方的加锁顺序是一样的

    说明:加上一把锁之后,在释放之前,不能再加锁。典型的锁中加锁的场景:OMU 代码中对几个容器的同时遍历,每个容器一把锁,就导致需要加多把锁。这种场景的解决方法:先加一把锁,对一个容器遍历,

    选择出合乎要求的数据,并保存在临时变量中;再加另一把锁,使用临时变量,再对其他容器遍历。锁中加锁,必须保证加锁的顺序是一样的,比如先加的锁后解锁,

    Lock1

    Lock2  

    Unlock2

    Unlock1

    则其他地方的加锁顺序,必须与这里的顺序一样,避免死锁,不允许出现:

    lock2

    lock1

    unlock2

    unlock1

    04  

    建议 10.1 进程间通讯,使用自己保证互斥的数据库系统、共享内存,或 socket 消息机制;尽量避免使用文件等进程无法管理的资源

    说明:由于文件在不同进程间访问,无法保证互斥。当然,可以在进程间加进程锁,但只受限于我们能加锁的进程,对于第三方进程等无法保证。这样,当多个进程同时对文件进行写操作时,将会导致

    文件数据破坏,或文件写失败等问题。

    数据库系统本身的访问接口带有互斥机制,当多个进程同时访问时,可以保证数据库数据的完整。

    共享内存,只限制于使用共享内存的几个进程,需要我们对这些问共享内存的进程加锁。但由于共享内存,第三方进程等无法访问,这也能比较好的保护数据,避免文件系统存在的问题。

    socket 消息机制,由操作系统 socket 通讯机制保证互斥,在多个进程间,通过消息来保证数据的互斥。 进程的消息都是操作系统转发而来的独立数据,属于进程私有数据,不存在进程间并行访问的问题。

    05  

    建议 10.2 可重入函数尽量只使用局部变量和函数参数,少用全局变量、静态变量

    说明:支持多线程并行访问的函数称之为可重入函数。设计可重入函数时,尽量使用局部变量和函数参数来传递数据,在多线程并行访问时,互相之间不会受影响。相反,如果使用全局变量、静态变量,就需要同步。

    示例:

      int iTotalCnt = 10;  void WriteFile()  {  for (int i=0; i<iTotalCnt; i++)  {  //写个数据到内存;}  iTotalCnt = 0; //写完数据之后,赋值计数为0  }

      上面的函数,如果是并行访问,将会导致有部分调用 WriteFile 的线程,不执行 for 循环;因为 iTotalCnt可能被其他线程修改为 0。

      引申:一些库函数也是非线程安全,调用时可能会出现多线程并发访问问题。

      06  

      建议 10.3 锁中避免调用函数;如果必须调用函数,务必保证不会造成死锁

      说明:这条规则是对加锁范围尽量小(只锁对应资源操作代码)规则的补充。不能把调用函数也加到加锁范围中。因为被调用函数的内部到底做了什么事情,是如何做的,调用者可能不是很清楚。尤其是当被调用函数内部又加锁的情况,就容易导致两个锁互饿,导致死锁。

      示例:

        Callfunc()  {  Lock2;  //….  Unlock2;  }  Thread_func1()  {  Lock1;  Callfunc();  Unlock1;  }  Thread_func2()  {  Lock2;  Lock1;  //…  Unlock1;  Unlock2}

        当上述线程函数 Thread_func1()和 Thread_func2()并行执行时,就很有可能导致死锁。而且这种死锁情况还是比较难分析。因为我们调用函数,很多时候只关注函数实现的功能,而忽略函数内部的具体实现。其次,锁中调用函数,也会把对资源操作的代码扩大化,不利于并行效率。更主要的是,这种操作,由于加锁的范围变大,引起死锁的可能就增大。

        07  

        建议 10.4 锁中避免使用跳转语句

        说明:跳转语句包含 return、break、continue、goto 等。如果锁中有宏调用的代码,要特别注意,分析宏中是否存在隐含的跳转语句。在函数返回时忘记把锁释放,特别是存在很多分支都可能返回的时候,

        可能一些分支会忘记释放锁。

        http://www.dtcms.com/a/492049.html

        相关文章:

      • 金华网站建设黄页wordpress修改后台样式
      • 网站锚文本wordpress 增加 推荐
      • 一周内从0到1开发一款安卓应用商店
      • 谷歌网站怎么做推广专业图库网站 西安
      • 自己做网站 教程韩国网页游戏网站
      • 三明交通建设集团网站飞鸟加速器
      • 【B树与B+树详解】
      • 哪个网站做ppt能赚钱个人养老保险12000元
      • 可以做兼职翻译的网站上海企业服务
      • LangExtract:基于LLM的信息抽取框架 学习笔记
      • 强化学习入门-3(AC)
      • Redis学习笔记-QuickList
      • C#循序渐进
      • 怎么做公司的官方网站网站做京东联盟
      • 网站开发 语音输入东莞网站设计品牌
      • 政务中心建设网站怎么做二级域名网站
      • 大坪网站公司佛山伦教网站设计
      • mysql基础【多表查询经典案例】
      • 智慧医疗新基建:医院三维可视化运维与IBMS集成探秘
      • 南昌网站网页设计广州手机网站定制信息
      • 网站建设工作会议.php语言网站开发
      • AI工程化:MLflow模型管理,生命周期怎样跟踪?
      • 抽象类需要用spring其他service,怎么写
      • SpringBoot-配置文件yaml
      • 一个网站设计的费用全国小学网站建设
      • so域名网站wordpress自动网站地址
      • Parasoft自动化测试工具与解决方案:实现规模化应用
      • 萧山网站建设微信 话潍坊站总站人工服务电话
      • 网站开发合同受托方wordpress中文主题站
      • STM32F103C8T6称重传感器HX711模块压力传感器称重的使用方法和代码驱动