Linux的进程间通信IPC方式,以及锁,原子操作,进程与线程
IPC原理:各自进程有不同的地址空间,任何一个进程的全局变量在另一个进程中并不可见,进程间想要交换数据必须通过内核。
先在内核开辟一块缓冲区,然后进程1将数据拷贝到内核缓冲区,进程2再把数据读走,这种机制被称为进程间通信机制。
- 匿名管道
四种特殊情况:
1)写端关,读端不关:剩余数据被读完后再读就返回0
2)写端不关,读端关:收到信号SIGPIPE,进程异常终止
3)写端不关,也不写数据,读端不关:读完再读会阻塞,直到有数据能够再读取并返回
4)写端不关,读端不关,也不读数据:写满再写会阻塞,直到有位置能够再写入并返回
缺点:一个管道只能单向通信,想要双向通信需要再创建一个管道或者使用sockpair;只能由于具有亲缘关系的IPC,例如父子,兄弟进程
- 命名管道
特点:存在于硬盘上的文件,使用时需要先用open打开,而匿名管道是存在于内存中的特殊文件;可以用于任何两个IPC,无论是否是父子进程或者有没有关系;无论是匿名管道还是命名管道,它们都使用了环形缓冲区来存储数据
参考:https://blog.csdn.net/weixin_62676865/article/details/130162356
- 消息队列
特点:与匿名管道,命名管道一样,从消息队列中读出数据,其中对应的数据都会被删除;可以实现消息的随机查询(按消息类型读取),不一定以先进先出的次序读取;每个消息队列中都有唯一的一个标识符;消息队列是消息的链表,存放于内存中,由内核维护,只有当内核重启或人工删除时,消息队列才会被删除,否则一直存在于系统中
同一个键值保证是同一个消息队列,同一个消息标识符保证不同的进程可以相互通信,同一个消息类型保证某个进程取出的是目标进程的信息。
- 共享内存
特点:最快,效率最高的方法;需要注意多个进程之间对一个给定的存储区访问的互斥,一般和信号量配合使用
- 信号量
主要是用来保护共享资源,以确保资源在一个时刻只被一个进程/线程所拥有。信号量的值为正时,表示空闲,有关线程可以锁定而使用它;若为0,表示被占用,有关线程需要进入睡眠队列等待被唤醒。
对低开销、短期、中断上下文加锁,优先考虑自旋锁;对长期、持有锁需要休眠的任务,优先考虑信号量。
(锁内容的补充:https://www.cnblogs.com/cxuanBlog/
由于在多处理器环境中某些资源的有限性,有时需要互斥访问,这时候就需要引入锁的概念,只有获取了锁的线程才能够对资源进行访问,由于多线程的核心是CPU的时间分片,所以同一时刻只能有一个线程获取到锁。那么就面临一个问题,那么没有获取到锁的线程应该怎么办?
通常有两种处理方式:一种是没有获取到锁的线程就一直循环等待判断该资源是否已经释放锁,这种锁叫做自旋锁,它不用将线程阻塞起来;还有一种处理方式就是把自己阻塞起来,等待重新调度请求,这种叫做互斥锁。
自旋锁效率高于互斥锁,但是在未获得锁时,一直进行自旋,如果不能在短时间内获得锁,无疑会大大降低CPU效率,自旋锁只在内核可抢占的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。)
信号量是一个特殊变量,程序对其访问都是原子操作,且只允许对它进行等待( P(sv) )和发送( V(sv) )信息操作,例如:对于两个进程共享信号量(sv),一旦其中一个进程执行了P(sv)操作,它将得到sv,并进入临界区,使sv-1,而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv=0,该进程会被挂起以等待,直到第一个进程离开临界区并执行V(sv)释放sv,这时第二个进程就可以恢复执行。
(原子操作:https://www.huliujia.com/blog/df3c2e8a9ef77bd2ed0d83292778734eb395970c/
原子操作指的是不可分割的操作。
在单核机器上,一个CPU指令能够完成的操作天然就是原子操作,比如MOV、INC等。比如++v是一个INC指令可以完成的操作,这就是一个原子操作。如果一个操作需要多个CPU指令才能够完成,这个操作就不是原子操作,可能会被中断,中断过程中外部可能修改这个操作的数据。
在多核机器上,一个CPU指令能够完成的操作不再是原子操作,因为指令读写的数据在缓存中,无法保证读到的数据是最新的,并且也无法保证指令完成后写入缓存的数据能够被其他核心“看见”。
x86架构中提供了LOCK指令前缀,LOCK前缀保证了指令不会受到其他核心的影响,保持原子性。这个是通过在指令执行时,限制其他核心访问相关数据,保证指令读到的是最新数据,写入数据后能够立刻被其他核心”看见”。)
(线程与进程的关系:进程时资源调度的基本单位,运行一个可执行程序会创建一个或多个进程,涉及CPU资源、内存资源、文件资源、句柄;线程是程序执行的基本单位,是轻量级的进程,每个进程中有且只有唯一的主线程,主线程与进程相互依存,主线程结束进程也会结束,涉及程序计数器、寄存器、栈、状态字;协程是线程内部调度的基本单位,是用户态的轻量级线程。)

浙公网安备 33010602011771号