热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《APUE》之进程篇

条件变量(ConditionVariable)CV有两个问题值得讨论:为什么有了mutex,仍需要condcond为什么一定要配合mutex使用为什么有了mutex,仍需要cond

条件变量(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都是半双工的。

《APUE》之进程篇


推荐阅读
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
author-avatar
燕阳阳消_469
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有