zoukankan      html  css  js  c++  java
  • 《APUE》之进程篇

    条件变量(Condition Variable)

    CV有两个问题值得讨论:

    1. 为什么有了mutex,仍需要cond
    2. cond为什么一定要配合mutex使用

    为什么有了mutex,仍需要cond

    mutex与cond的适用场景并不同,mutex是控制shared resource在任一时刻只能由一个线程访问。

    而cond实现了一种通知机制,当某个条件满足,则唤醒等待在这个条件的线程继续执行。如果使用mutex模拟cond,代码将会是这样:

    Thread1:

    while(1) {
        lock(mutex); // Blocks waiting for notification from Thread2
        ... // do work after notification is received
        unlock(mutex); // Tells Thread2 we are done
    }

    Thread2:

    while(1) {
        ... // do the work that precedes notification
        unlock(mutex); // unblocks Thread1
        lock(mutex); // lock the mutex so Thread1 will block again
    }

    这个实现存在问题:

    1. 在Thread1做完“do work after notification”前,Thread2将不能进行“do work precedes notification”工作,因为mutex未释放,Thread2 block在lock(mutex)处。这种情况,将“do work after notification”和“do work precedes notification”放在同一个线程显然更合适。
    2. 如果Thread2不能抢占mutex,Thread1将会re-lock并继续执行,但此时它并没有收到notification,这与语义不符。虽然我们可以利用操作系统一些机制,比如在Thread1中sleep来控制Thread1和Thread2 lock的先后顺序,但这是一个糟糕的设计。

    上述mutex实现方案的重大缺陷,就是cond存在的意义。

    refer: https://stackoverflow.com/questions/12551341/when-is-a-condition-variable-needed-isnt-a-mutex-enough

    cond为什么一定要配合mutex使用

    如果在改变条件和发送信号前不加锁,将可能导致唤醒信号丢失,考虑下面情况:

    Thread1:

    pthread_mutex_lock(&mutex);
    while (condition == FALSE)
        pthread_cond_wait(&cond, &mutex);
    pthread_mutex_unlock(&mutex);

    Thread2:(不加锁的错误实现)

    condition = TRUE;
    pthread_cond_signal(&cond);

    假定condition初始值为FALSE,Thread1和Thread2两个线程代码交替执行,则可能发生下面情况:

    Thread1                               Thread2
    
    pthread_mutex_lock(&mutex);
    while (condition == FALSE)
    
                                          condition = TRUE;
                                          pthread_cond_signal(&cond);
    
    pthread_cond_wait(&cond, &mutex);

    此时condition为TRUE,但由于pthread_cond_wait未执行,也就是Thread1并没有在cond的等待队列中,将导致Thread2的pthread_cond_signal发出的唤醒信号丢失,Thread1将一直block在pthread_cond_wait上面。

    而如果在Thread2中加锁:

    pthread_mutex_lock(&mutex);
    condition = TRUE;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

    这样唤醒信号将永远不会丢失。其中pthread_cond_wait的实现逻辑为:

    1. 将线程放入cond等待队列
    2. unlock mutex
    3. 等待唤醒信号唤醒
    4. lock mutex并返回

    refer: https://stackoverflow.com/questions/12551341/when-is-a-condition-variable-needed-isnt-a-mutex-enough

    进程间通信IPC(interprocess communication)

    Linux进程间通信分为几类:

    1。管道(pipe)和FIFO(命名管道)

    2。XSI IPC:消息队列,信号量(只是一种进程同步原语,配合共享内存等IPC使用),共享内存

    3。网络套接字(用于跨机器通信)

    4。UNIX域套接字(与网络socket类似,使用同一套API,但只能单机进程间通信。优点是免去了网络套接字协议处理部分,不需要添加或删除网络报头,无需计算检验和,不要产生顺序号,无需发送确认报文,因此效率更高)

    这里说一下XSI IPC与其它几类IPC的比较。

    内核中,每个XSI IPC结构,都使用一个非负数的标识符加以引用。例如,为了对一个消息队列发送或取消息,只需要知道其队列标识符。与文件描述符不同,IPC标识符不是小的整数。当一个IPC结构被创建(下面讨论的都专指 3种XSI IPC:消息队列、信号量和共享内存),以后又被删除时,与这个结构相关的标识符连续加1,直至达到一个整数型的最大正值,然后又回转到0.

    标识符是IPC对象的内部名。为了使IPC对象可以被多个进程使用,需要提供一个外部名方案。为此使用了键(key),每个IPC对象都与一个键相关联,于是键就用作该对象的外部名。

    XSI IPC还为每个IPC结构设置了一个ipc_perm结构。该结构规定了权限和所有者。

    XSI IPC的主要问题是:

    1。IPC结构是在系统范围内起作用的,没有访问计数。例如,如果进程创建了一个消息队列,凌晨在该队列放个几则消息,然后终止。但是该消息队列和消息不会被删除。

    2。这些IPC结构在文件系统没有名字。我们不能通过open,write,read,fcntl,close等函数来操作他们,为了支持这些功能 ,不得不增加十几条全新的系统调用。我们不能用ls命令见到IPC对象,不能使用rm命令删除他们,也不能通过chmod来修改他们的权限。于是不得不增加ipcs()和ipcrm命令。

    3。因为这些IPC不使用文件描述符,所以不能对他们使用多路转接I/O函数:select和pool。

    总之,Stevens认为XSI IPC的设计是不好的。

    在IPC选择方面,他给了以下一些建议:

    要学会使用管道和FIFO,因为在大量应用程序中级可有效地使用这两种基本技术。在新的应用程序中,要尽可能避免使用消息队列以及信号量,而应当考虑全双工管道和记录锁,他们使用起来会简单得多。共享内存有其应用场合,而mmap函数也能提供同样的功能。

    值得注意的是,Linux的全双工管道使用UNIX域套接字实现(socketpair) 。默认管道和FIFO都是半双工的。

  • 相关阅读:
    MM1排队系统
    java基本概念
    将博客搬至CSDN
    数据库知识点1
    离散分布
    概率论1--基本概念
    一道经典JS题(关于this)
    ajax请求过程中下载文件在火狐下的兼容问题
    熟悉css/css3颜色属性
    打字机游戏Ⅱ之手速pk
  • 原文地址:https://www.cnblogs.com/gm-201705/p/12897934.html
Copyright © 2011-2022 走看看