• 线程程序里不准使用fork ?


    其实这是 UNIX上C++程序设计守则3

    准则3:多线程程序里不准使用fork
    在多线程程序里,在”自身以外的线程存在的状态”下一使用fork的话,就可能引起各种各样的问题.比较典型的例子就是,fork出来的子进程可能会死锁.请不要,在不能把握问题的原委的情况下就在多线程程序里fork子进程.
    那看看实例吧.一执行下面的代码,在子进程的执行开始处调用doit()时,发生死锁的机率会很高.
    void*doit(void*) {
       static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
       pthread_mutex_lock(&mutex);
       struct timespec ts = {10, 0}; nanosleep(&ts, 0); // 10秒寝る
                                                        // 睡10秒
       pthread_mutex_unlock(&mutex);
       return 0;
    }

    int main(void) {
           pthread_t t;

           pthread_create(&t, 0, doit, 0);                               // 做成并启动子线程
           if (fork() == 0) {
                 //子进程
                //在子进程被创建的瞬间,父的子进程在执行nanosleep的场合比较多
                 doit(0);

                 return 0;
           }
           pthread_join(t, 0); //
            // 等待子线程结束
    }

    以下是说明死锁的理由
    一般的,fork做如下事情
       1. 父进程的内存数据会原封不动的拷贝到子进程中
       2. 子进程在单线程状态下被生成


    在内存区域里,静态变量mutex的内存会被拷贝到子进程里.而且,父进程里即使存在多个线程,但它们也不会被继承到子进程里. fork的这两个特征就是造成死锁的原因.
    译者注: 死锁原因的详细解释 ---
       1. 线程里的doit()先执行.
       2. doit执行的时候会给互斥体变量mutex加锁.
       3. mutex变量的内容会原样拷贝到fork出来的子进程中
    (在此之前,mutex变量的内容已经被线程改写成锁定状态).
       4.子进程再次调用doit的时候,在锁定互斥体mutex的时候会发现它已经被加锁,所以就一直等待,直到拥有该互斥体的进程释放它(实际上没有人拥有这个mutex锁).
       5.线程的doit执行完成之前会把自己的mutex释放,但这是的mutex和子进程里的mutex已经是两份内存.所以即使释放了mutex锁也不会对子进程里的mutex造成什么影响.

    直到目前为止,已经写上了thread+fork是危险的,但是有一个特例需要告诉大家.”fork后马上调用exec的场合,是作为一个特列不会产生问题的”. 什么原因呢..?exec函数*6一被调用,进程的”内存数据”就被临时重置成非常漂亮的状态.因此,即使在多线程状态的进程里,fork后不马上调用一切危险的函数,只是调用exec函数的话,子进程将不会产生任何的误动作.但是,请注意这里使用的”马上”这个词.即使exec前仅仅只是调用一回printf(“I’mchild process”),也会有死锁的危险.
    译者注:exec函数里指明的命令一被执行,该命令的内存映像就会覆盖父进程的内存空间.所以,父进程里的任何数据将不复存在.

    本blog的理解:查看前面进程创建中,子进程在创建后,是写时复制的,也就是子进程刚创建时,与父进程一样的副本,当exce后,那么老的地址空间被丢弃,而被新的exec的命令的内存的印像覆盖了进程的内存空间,所以锁的状态无关紧要了。


    多线程程序里不使用fork是值得推荐的.


    其实我们还是可以在多线程是时候用fork()函数的,但是如何规避灾难呢?

    为了在多线程的程序中安全的使用fork,而规避死锁问题的方法有吗?试着考虑几个.

    规避方法1:做fork的时候,在它之前让其他的线程完全终止.
           在fork之前,让其他的线程完全终止的话,则不会引起问题.但这仅仅是可能的情况.还有,因为一些原因而其他线程不能结束就执行了fork的时候,就会是产生出一些解析困难的不具合的问题.

    规避方法2:fork后在子进程中马上调用exec函数

           不用使用规避方法1的时候,在fork后不调用任何函数(printf等)就马上调用execl等,exec系列的函数.如果在程序里不使用”没有exec就fork”的话,这应该就是实际的规避方法吧.
    译者注:笔者的意思可能是把原本子进程应该做的事情写成一个单独的程序,编译成可执行程序后由exec函数来调用.

    规避方法3:”其他线程”中,不做fork-unsafe的处理
           除了调用fork的线程,其他的所有线程不要做fork-unsafe的处理.为了提高数值计算的速度而使用线程的场合*7,这可能是fork- safe的处理,但是在一般的应用程序里则不是这样的.即使仅仅是把握了那些函数是fork-safe的,做起来还不是很容易的.fork-safe函数,必须是异步信号安全函数,而他们都是能数的过来的.因此,malloc/new,printf这些函数是不能使用的.

  • 相关阅读:
    SharePoint 2013 中的SQL Server 安全
    SharePoint 2013 的HTML5特性之响应式布局
    SharePoint 2013 一些小技巧
    SharePoint 2013 排错之"Code blocks are not allowed in this file"
    SharePoint 2013 创建搜索中心及搜索设置
    SharePoint 2013 使用PowerShell创建State Service
    SharePoint 2013 内容部署功能简介
    SharePoint 使用PowerShell恢复误删的网站集
    SharePoint 自定义WebPart之间的连接
    linux之misc及使用misc创建字符设备
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6333016.html
Copyright © 2020-2023  润新知