Skip to content

1158114251/Linux_api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Linux_api

说明

1.主要谈谈进程通信相关的系统api,对于进程而言,由于操作系统和硬件的实现,已经尽可能的隔离各个进程,在32位操作系统中,各个进程拥有自己的4GB空头支票。当然上个月的CPU熔断漏洞,也算是由于其他问题而导致在进程隔离上出现了问题。其实对于进程通信,首要任务是要让俩个进程有共同的可以联系的纽带,标识。当然还是刚才谈到的由于操作系统的设计初衷就是进程完全隔离,而这个纽带就费劲了,于是有了什么有名管道,通过fork调用,这种进程数据结构的拷贝机制(写时拷贝),可以让父子进程拥有共同的文件描述符,还有通过磁盘文件,总而言之:就是在内核数据结构上产生共同的索引标识。达到通信。

具体而言主要有这几个,其中2,3,4 是系统5的进程通信的几种机制:

1.管道

2.共享内存(Shared Memory)

3.信号量集(Semaphore Arrays)

4.消息队列(Message Queues)

  • man msgget
  • man msgop
  • man msgctl

函数接口我们可以通过man手册查看

  • man semget
  • man semop
  • man semctl
  • man shmget
  • man shmop
  • man shmctl

2.优缺点,如何考量

  • 管道

管道的优点是不需要加锁,缺点是默认缓冲区太小,只有4K,同时只适合父子进程间通信,而且一个管道只适合单向通信,如果要双向通信需要建立两个。而且不适合多个子进程,因为消息会乱,它的发送接收机制是用read/write这种适用流的,缺点是数据本身没有边界,需要应用程序自己解释,而一般消息大多是一个固定长的消息头,和一个变长的消息体,一个子进程从管道read到消息头后,消息体可能被别的子进程接收到。简单通信可以。

  • 消息队列

消息队列也不要加锁,默认缓冲区和单消息上限都要大一些,在我的suse10上是64K,它并不局限于父子进程间通信,只要一个相同的key,就可以让不同的进程定位到同一个消息队列上,它也可以用来给双向通信,不过稍微加个标识,可以通过消息中的type进行区分,比如一个任务分派进程,创建了若干个执行子进程,不管是父进程发送分派任务的消息,还是子进程发送任务执行的消息,都将type设置为目标进程的pid,因为msgrcv可以指定只接收消息类型为type的消息,这样就实现了子进程只接收自己的任务,父进程只接收任务结果

  • 共享内存

共享内存的几乎可以认为没有上限,它也是不局限与父子进程,采用跟消息队列类似的定位方式,因为内存是共享的,不存在任何单向的限制,最大的问题就是需要应用程序自己做互斥,有如下几种方案

1 只适用两个进程共享,在内存中放一个标志位,一定要声明为volatile,大家基于标志位来互斥,例如为0时第一个可以写,第二个就等待,为1时第一个等待,第二个可以写/读

2 也只适用两个进程,是用信号,大家等待不同的信号,第一个写完了发送信号2,等待信号1,第二个等待信号2,收到后读取/写入完,发送信号1,它不是用更多进程是因为虽然父进程可以向不同子进程分别发送信号,但是子进程收到信号会同时访问共享内存,产生不同子进程间的竞态条件,如果用多块共享内存,又存在子进程发送结果通知信号时,父进程收到信号后,不知道是谁发送,也意味着不知道该访问哪块共享内存,即使子进程发送不同的结果通知信号,因为等待信号的一定是阻塞的,如果某个子进程意外终止,父进程将永远阻塞下去,而不能超时处理

3 采用信号量或者msgctl自己的加锁、解锁功能,不过后者只适用于linux

  • 总结

管道是最弱的,只适合有限场景; 消息队列能适合大部分场景,缺点是默认缓冲也比较小,不过这个可以调整,前提是你有管理员权限; 共享内存不错,但是要做同步。