• 进程间通信——实现


    以UNIX为例来分析进程间通信的各种实现技术。

    在UNIX中,文件(File)、信号(Signal)、无名管道(Unnamed Pipes)、有名管道(FIFOs)是传统IPC功能;新的IPC功能包括消息队列(Message queues)、共享存储段(Shared memory segment)和信号量(Semapores)。

    1.信号

      信号机制是UNIX为进程中断处理而设置的。它只是一组预定义的值,因此不能用于信息交换,仅用于进程中断控制。例如在发生浮点错、非法内存访问、执行无 效指令、某些按键(如ctrl-c、del等)等都会产生一个信号,操作系统就会调用有关的系统调用或用户定义的处理过程来处理。信号处理的系统调用是signal,调用形式是:

      signal(signalno,action),其中,signalno是规定信号编号的值,action指明当特定的信号发生时所执行的动作。

     

    2.无名管道

      管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。无名管道是一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,并且只存在与内存中。下面是生成管道的函数原型:

    #include <unistd.h>
    int pipe(int fd[2])

      fd[0]中返回管道的读通道打开文件描述等,在fd[1]中返回管道的写通道打开文件描述符。

      该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由 pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信。

      向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

      只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

    3.有名管道

      不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据。

       下面是创建有名管道的函数原型:

    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char * pathname, mode_t mode)

      该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如closereadwrite等等。

    4.消息队列

      消息队列是内存中独立于生成它的进程的一段存储区,一旦创建消息队列,任何进程,只要具有正确的的访问权限,都可以访问消息队列,消息队列非常适合于在进程间交换短信息。

      消息队列的每条消息由类型编号来分类,这样接收进程可以选择读取特定的消息类型——这一点与管道不同。消息队列在创建后将一直存在,直到使用msgctl系统调用或iqcrm -q命令删除它为止。

      下面是关于消息队列的API:

    //创建一个具有flag权限的MQ及其相应的结构,并返回一个唯一的正整数msqid(MQ的标识符); 
    int msgget(key,flag)
    
    //向队列中发送信息;
    int msgsnd(msqid,msgp,msgsz,msgtyp,flag)
    
    //从队列中接收信息;
    int msgrcv(msqid,cmd,buf)
    
    //对MQ的控制操作;
    int msgctl(msqid,cmd,buf)

    5.共享存储段

      共享存储段是主存的一部分,它由一个或多个独立的进程共享。

      下面是关于共享存储段的API

    //创建大小为size的SM段,其相应的数据结构名为key,并返回共享内存区的标识符shmid;
    int shmget(key,size,flag)
    
    //将当前进程数据段的地址赋给shmget所返回的名为shmid的SM段;
    char shmat(shmid,address,flag)
    
    //从进程地址空间删除SM段;
    int shmdr(address)
    
    //对SM的控制操作;
    int shmctl (shmid,cmd,buf)

    6.信号量

      在UNIX中,信号灯是一组进程共享的数据结构,当几个进程竞争同一资源时(文件、共享内存或消息队列等),它们的操作便由信号灯来同步,以防止互相干扰。

      信号灯保证了某一时刻只有一个进程访问某一临界资源,所有请求该资源的其它进程都将被挂起,一旦该资源得到释放,系统才允许其它进程访问该资源。信号灯通常配对使用,以便实现资源的加锁和解锁。

  • 相关阅读:
    【洛谷5304】[GXOI/ZOI2019] 旅行者(二进制分组+最短路)
    【LOJ6485】LJJ 学二项式定理(单位根反演)
    【CF932E】Team Work(第二类斯特林数简单题)
    【CF960G】Bandit Blues(第一类斯特林数)
    【洛谷4689】[Ynoi2016] 这是我自己的发明(莫队)
    【洛谷5355】[Ynoi2017] 由乃的玉米田(莫队+bitset)
    【洛谷5268】[SNOI2017] 一个简单的询问(莫队)
    【洛谷4688】[Ynoi2016] 掉进兔子洞(莫队+bitset)
    【洛谷3653】小清新数学题(数论)
    【洛谷6626】[省选联考 2020 B 卷] 消息传递(点分治基础题)
  • 原文地址:https://www.cnblogs.com/yitong0768/p/4563168.html
Copyright © 2020-2023  润新知