linux多线程编程的七条准则

标签: linux 多线程 编程 | 发表时间:2011-07-30 06:16 | 作者:BusyCai MadFrog
出处:http://blog.csdn.net
  • 准则1:不依赖于信号收发的设计。原文
    • 给其它进程以及自己发送异步信号并改变处理流程的设计不要做。
    • 不要把信号和线程一起使用,这将使得程序动作的预测和调试变得困难。
  • 准则2:要知道信号处理函数中可以做哪些处理。原文
    • 在sigaction()函数登记的信号处理函数中可以做的处理是被严格限定的。仅允许:
      • 局部变量的相关处理
      • volatile sig_atomic_t类型的全局变量操作
      • 调用异步信号安全的相关函数
  • volatile提示编译器对此变量不要进行优化处理,因为优化后代码可能导致程序语句的顺序混乱。sig_atomic_t类型变量表示只需要一条机器指令就可以执行完成,这样保证了操作的原子性。
  • 可重入函数,百度百科。简单来说,就是允许该函数有多个副本同时运行;可以在函数执行的任意时刻中断它,而返回时不会出现错误。不可重入函数由于使用/正占有一些系统资源(如全局变量/静态变量等等),如被中断则可能出现问题(如死锁),因此不能运行在多线程环境下。printf是一个不可重入函数,因为printf函数内部调用了malloc函数,而malloc之前会利用静态mutex对其进行lock。设想这样一种情况,某线程在调用printf(内部执行至对静态mutex加锁操作)时中断,而在信号处理函数中同样调用了printf,则会产生死锁。
  • 信号处理函数中调用的函数必须是可重入函数。
  • 异步信号安全(async-signal-safe)函数是指在该函数内部即使因为信号而正在被中断,在其它地方该函数再次被调用时也不会有任何问题。不可重入函数就不是异步信号安全函数。
准则3:多线程程序里不准使用fork。原文
  • 一般fork做如下事情:
    • 父进程的内存数据会原封不动地copy到子进程中。
    • 子进程在单线程状态下被生成。
  • fork导致子进程死锁的典型情景:
    • 父进程调用某函数foo,foo内部锁定了自己的mutex
    • fork,子进程copy了父进程的mutex
    • 子进程调用foo,此时子进程的mutex处于锁定状态,而它是父进程mutex的一个副本,与父进程的mutex没有关系了,没人可以解开它了。
    • 子进程再次锁定已经处于锁定状态的子进程mutex,导致死锁产生。
  • 如何规避灾难:
    • 多纯种程序里不使用fork
    • fork之后紧跟exec,使得子进程的内存状态被exec指定的命令所重置。
准则4:不要做线程的异步撤消的设计。原文
     异步撤消是指:某个线程的执行立刻被其它线程所终止了。
     请不要单单为了让设计更简单或者看起来更简单而使用异步撤消设计。
     一个异步撤消设计导致死锁的场景:
          线程1调用malloc正在做内存分配时,线程2异步撤消了线程1的执行。
          线程1马上被撤消,但malloc中的mutex互斥锁没有被解除。
          后面任意一个线程调用malloc都会导致死锁。
     如何避免这些问题?
          使用pthread_cleanup_push函数,登记异步撤消时的线程数据消除的回调函数。但其对延迟撤消不能调用。
          不要执行异步撤消处理。
准则5:尽可能避免线程的延迟撤消处理。原文
     和异步撤消不同,延迟撤消的撤消处理会一直延迟到代码上明示的撤消点之后才会被执行。
     能否成为撤消点跟具体的函数实现也有关系,因此延迟撤消的自由度较高,需要考虑OS和C库版本、运行环境等等。
     若撤消点位于lock-unlock之间,则可能会导致死锁。为了回避这个问题,注意利用pthread_cleanup_push函数在撤消时释放掉互斥锁。
     C++与延迟撤消的兼容度非常差,在使用C++的工程里不使用延迟撤消还是比较实际的。
准则6:遵守多线程编程的常识。原文1原文2
     多线程环境下,非线程安全的函数,一定不要使用。
     要让自己编写的函数符合线程安全:
          在访问共享数据之前一定要先锁定。
          如果C++的话,一定要注意函数的同步方法。
     线程安全函数,是像下面这样:
          不要操作局部的静态变量和全局变量,并且其它的非线程安全函数不要调用。
          要操作这样的变量的话,就要用mutex进行同步处理,来限制多个线程同时对其进行操作。

作者:BusyCai 发表于2011-7-29 23:16:17 原文链接
阅读:73 评论:0 查看评论

相关 [linux 多线程 编程] 推荐:

linux多线程编程的七条准则

- MadFrog - CSDN博客推荐文章
准则1:不依赖于信号收发的设计. 给其它进程以及自己发送异步信号并改变处理流程的设计不要做. 不要把信号和线程一起使用,这将使得程序动作的预测和调试变得困难. 准则2:要知道信号处理函数中可以做哪些处理. 在sigaction()函数登记的信号处理函数中可以做的处理是被严格限定的. 仅允许: 局部变量的相关处理.

[原]Java多线程中的synchronized、volatile和无锁编程

- - Snowball
新建状态(New):新创建了一个线程对象. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法. 该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权. 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行.

python编程:深入理解 Python 中的多线程 新手必看

- - Seay's blog 小屌丝守护着信息安全、
我们将会看到一些在Python中使用线程的实例和如何避免线程之间的竞争. 你应当将下边的例子运行多次,以便可以注意到线程是不可预测的和线程每次运行出的不同结果. 声明:从这里开始忘掉你听到过的关于GIL的东西,因为GIL不会影响到我想要展示的东西. 我们将要请求五个不同的url:. 除非cpu从一个url获得了回应,否则不会去请求下一个url.

Linux 编程和系统管理新手入门

- - 操作系统 - ITeye博客
developerWorksLinux 专区 有数百篇技术文章、教程和小技巧,是 Linux 应用开发和系统管理的宝藏,但对于试图有自己选择方向的读者来说,找到所有需要的信息却很不易. 本页对想学习 Linux 但又无从下手的读者提供了综述指导,提供了 Linux 基础知识,并把相关的 developerWorks 文章、教程、技巧以及 IBM 培训服务教学、讲座实习和 IBM 产品集结在一起,以利于您进一步学习.

开源软件实践之linux高性能服务器编程框架和选型(续)

- - CSDN博客架构设计推荐文章
    接着昨天的Proactor模式介绍.      proactor模式将所有IO操作交给主线程和linux内核来处理,工作线程负责业务逻辑. 异步IO实现这种模式的工作流程如下:. 1)主线程使用aio_read函数注册socket读完成事件,提供用户接收数据的缓冲区地址以及读操作完成时如何通知应用程序(有信号等手段);.

Java Thread多线程

- - CSDN博客推荐文章
Java Thread多线程. Java 多线程例子1 小例子. super("zhuyong");//设置线程的名字,默认为“TestThread”. Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 ). 1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程).

Javascript 里跑Linux

- rockmaple - Shellex's Blog
牛逼到暴的大拿 Fabrice Bellard,用Javascript实现了一个x86 PC 模拟器,然后成功在这个模拟器里面跑Linux(请用Firefox 4 / Google Chrome 11打开,Chome 12有BUG). 关于这个东西… 伊说 “I did it for fun“,大大啊大大啊….

Linux Ksplice,MySQL and Oracle

- Syn - DBA Notes
Oracle 在 7 月份收购了 Ksplice. 使用了 Ksplice 的 Linux 系统,为 Kernel 打补丁无需重启动,做系统维护的朋友应该明白这是一个杀手级特性. 现在该产品已经合并到 Oracle Linux 中. 目前已经有超过 700 家客户,超过 10 万套系统使用了 Ksplice (不知道国内是否已经有用户了.

linux makefile编写

- hl - C++博客-首页原创精华区
在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则. target也就是一个目标文件,可以是Object File,也可以是执行文件. prerequisites就是,要生成那个target所需要的文件或是目标. command也就是make需要执行的命令. 这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在 command中.

Linux下的VDSO

- 圣斌 - Adam's
VDSO(Virtual Dynamically-linked Shared Object)是个很有意思的东西, 它将内核态的调用映射到用户态的地址空间中, 使得调用开销更小, 路径更好.. 开销更小比较容易理解, 那么路径更好指的是什么呢. 拿x86下的系统调用举例, 传统的int 0×80有点慢, Intel和AMD分别实现了sysenter, sysexit和syscall, sysret, 即所谓的快速系统调用指令, 使用它们更快, 但是也带来了兼容性的问题.