Linux应用开发 04 进程间通讯

一. 进程间通讯(IPC)
  1.  什么是进程间通讯(IPC)?
       多个进程之间进行的信息的传递与就换的过程。
  2.  进程间通讯的目的?
       2.1  数据通讯
       2.2  事件通知
       2.3  资源同步
       2.4  进程控制
  3.  进程间通讯方式:
       1)  管道
       2)  共享内存
       3)  消息队列
       4)  信号量
       5)  信号
       6)  套接字
   4.  管道:
        内核提供的具有读写两端的通讯通道;
    特点: 1. 单向的,先进先出
           2. 读取后的数据将不存在于管道中
           3. 管道具有简单的流控制机制
               4. 管道容量默认 64KB

        4.1   无名管道 (匿名管道)
              优点: 操作简单,创建管道就可以获取管道读写两端描述符
                 管道读写可借助 read write系统IO函数进行;
          缺点: 1. 使用场景受限,只能应用于具有亲缘关系的进程之间;
                 2. 要完成完整的数据读写,一般要借助于两个管道;
             3. 管道容易造成阻塞

               pipe
        头文件:   #include <unistd.h>
        函数原型: int pipe(int fd[2]);
        函数功能:  创建匿名管道,获取读写描述符
        函数参数: 用于获取读写描述符
        函数返回值: 成功返回 -1;
                     失败 :返回-1.  错误码存放在 errno 

     4.2   有名管道 (命名管道)

            创建管道的进程可以给管道命名(提供系统路径),以后对管道的操作,是通过
                管道路径来实现;
        管道路径是一个特殊的文件,和普通一样具有文件路径,访问属性,但不同处在于
                管道文件是不能存储数据的,数据往往是存储在内存中的;

                特点: 1. 对管道的访问要同时存在读和写进程,否则进程阻塞;
               2. 如果存在读写进程完整打开命名管道,
                 读操作以以下方式进行:
                  1) 管道中无数据,读进程阻塞
              2)  管道中有数据 不管数据大小是否满足读取的需要,则读操作都不会阻塞
              写操作以以下方式进行:
                  1) 管道中无空间,写进程阻塞
              2)  管道中有空间, 但不足以满足写入数据的需要,则写操作阻塞

              中途有进程退出:
               1) 退出的读进程,则写进程在不处理 SIGPIPE情况下,写进程会强制终止;
               2) 退出的写进程,则读进程read 函数会返回0,但读进程不阻塞;
              
          使用场景: 命名管道可以应用于所有的进程。

          创建命名管道:
            mkfifo

        头文件:   #include <sys/types.h>
                   #include <sys/stat.h>
        函数原型: int mkfifo(const char* pathname,mode_t mode);
        函数功能:  创建命名管道
        函数参数: pathname:给创建的命名管道指定管道路径
                   mode:     指定管道文件的访问权限
        函数返回值: 成功返回 -1;
                     失败 :返回-1.  错误码存放在 errno 

     5.  共享内存
          共享内存是一块独立于进程地址空间之外,可供多个进程共同访问的物理内存。
      优势: 1. 操作简单,效率高
             2. 数据共享,可减少数据传递及数据拷贝
         3. 容量大
          缺点:
                 1. 共享内存存在同步问题,用户可利用信号量来提供同步机制。

      共享内存访问步骤:
       1.  申请共享内存;
            shmget
                头文件:       #include <sys/ipc.h>
                                      #include <sys/shm.h>

            函数原型:   int  shmget(key_t key,size_t size,int shmflg);
            函数功能:   创建或者获取共享内存
            函数参数:   key :         获取共享内存的关键字,
                                   该关键字是创建共享内存时,由创建进程指定
                                                   key: 可取值为:
                                1. IPC_PRIVATE:  总是创建
                                                        2. ftok函数的返回值
                                     size:        申请共享内存的大小
                     shmflg :     共享内存标志:
                                   IPC_CREAT 
                           IPC_EXCL
                           还可用于指定共享内存的权限

            函数返回值:  成功  : 共享内存的标识符
                         失败  : -1

            例子: shmget(key,1024,IPC_CREAT | IPC_EXCL | 0644)
       2.  内存映射
             shmat  
                头文件:       #include <sys/ipc.h>
                                      #include <sys/shm.h>

            函数原型:   void*  shmat(int shmid,const void* shmaddr,int shmflg);
            函数功能:   映射共享内存到进程地址空间
            函数参数:   
                         shmid :        共享内存的标识符,
                                     shmaddr:      映射地址,NULL代表由系统决定
                     shmflg :      映射后内存操作方式:
                                    SHM_RDONLY: 只读
                                                    其他读写,  往往写 0;
            函数返回值:  成功  : 实际映射后的内存地址
                         失败  : (void*)-1

       3.  地址空间访问
       4.  解除映射
             shmdt  
                头文件:       #include <sys/ipc.h>
                                      #include <sys/shm.h>
            函数原型:   int  shmdt(const void* shmaddr);
            函数功能:   映射共享内存到进程地址空间
            函数参数:              
                                     shmaddr:      映射地址(shmat 返回值)
                    
            函数返回值:  成功  : 0
                         失败  : -1
       5.  回收共享内存。
             shmctl
                        头文件:       #include <sys/ipc.h>
                                      #include <sys/shm.h>
            函数原型:   int  shmctl(int shmid,int cmd, struct shmid_ds *buf);
            函数功能:   控制共享内存运行
            函数参数:   shmid:   共享内存的标识符          
                                     cmd:     控制方式  (常用)
                               IPC_STAT    获取状态信息
                           IPC_SET     设置状态信息  权限
                                               IPC_RMID    回收共享内存    
                     buf:     共享内存信息结构体,用于存放获取到的,待设置的信息;
            函数返回值:  成功  : 0
                         失败  : -1
      延伸知识:   IPC 标准:

          1.  SystemV   AT&T  
          2.  Posix     IEEE    

   5.  信号量
       
         作用:  信号量在进程间通讯中,并不是进行数据通讯,而是提供资源访问的同步机制;

     信号量:内核提供的一种用于进程同步的一种机制,本质是一个非负的整数计数器,
             特点是:当信号量计数为 < 0 时候,信号量会阻塞进程。

         信号量PV原语(原子操作):
     P操作原语:  信号量-1, 若对计数值为0的信号量做P操作,则进程阻塞
     V操作原语:  信号量+1   V操作后,信号量计数值为>=0的时, 进程可被唤醒

     SystemV 标准的信号量其实是一个信号量集合:

     基本操作:
       1.   创建或者获取信号量集合:

            semget
                头文件:       #include <sys/ipc.h>
                                      #include <sys/sem.h>
                      #include <sys/types.h>

            函数原型:   int  semget(key_t key,int nsems,int semflg);
            函数功能:   创建或者获取信号量集合
            函数参数:   key :         获取信号量集的关键字,
                                   该关键字是创建信号量集时,由创建进程指定
                                                   key: 可取值为:
                                1. IPC_PRIVATE:  总是创建
                                                        2. ftok函数的返回值
                                     nsems:       指定申请的信号量个数
                     semflg :     信号量集标志:
                                   IPC_CREAT 
                           IPC_EXCL
                           还可用于指定信号量集的权限

            函数返回值:  成功  : 信号量集的标识符
                         失败  : -1  

     2.   信号量集合操作:

                semop
                     头文件:       #include <sys/ipc.h>
                                           #include <sys/sem.h>
                                           #include <sys/types.h>

                 函数原型:   int semop(int semid, struct sembuf sops[], unsigned nsops);
                             函数功能:   对信号量集合中的信号量进行 PV操作 
                 函数参数:   
                         semid :       信号量集的描述符,
                                     sops:        struct sembuf 类型的数据,描述对信号量的具体操作
                     nsops :      sops 数组元素的个数

                 函数返回值:  成功  : 0
                              失败  : -1
 
                  
       3.  信号量控制(回收)           
              semctl
                 
                 头文件:       #include <sys/ipc.h>
                                           #include <sys/sem.h>
                                           #include <sys/types.h>

                 函数原型:    int semctl(int semid, int semnum, int cmd, ...);
                             函数功能:    对信号量集合进行控制 
                 函数参数:   
                         semid :       信号量集的描述符,
                                     semnum:      信号量集中信号的编号
                     cmd :        控制方式:                                   
                           IPC_RMID
                                                   SETVAL:   用于设置单个信号量的计数值
                                     此次第四个参数为如下的自定义联合体 

                           union semun 
                           {
                               int              val;    /* Value for SETVAL */
                               struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                               unsigned short  *array;  /* Array for GETALL, SETALL */
                               struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
                           };

                           利用该联合体中 val 成员进行计数值的设置

                 函数返回值:  成功  : 0
                              失败  : -1
6.  消息队列(msgqueue)

        消息队列是来实现进程间数据通讯的;

    优点:不存在同步问题的,
    缺点: 容量小。适合发送短数据

    消息队列本质是一个消息链表,对于消息队列来说。存放在队列中的消息
    需要指定消息类型,接收进程也是通过消息类型来接收发自不同进程的消息数据;


    消息队列操作:
      1.  创建消息队列:
            msgget
                头文件:       #include <sys/ipc.h>
                                      #include <sys/msg.h>
                      #include <sys/types.h>

            函数原型:   int  msgget(key_t key,int msgflg);
            函数功能:   创建或者获取消息队列
            函数参数:   key :         获取消息队列的关键字,
                                   该关键字是创建消息队列时,由创建进程指定
                                                   key: 可取值为:
                                1. IPC_PRIVATE:  总是创建
                                                        2. ftok函数的返回值
                                     
                     msgflg :     消息队列标志:
                                   IPC_CREAT 
                           IPC_EXCL
                           还可用于指定信号量集的权限

            函数返回值:  成功  : 消息队列的标识符
                         失败  : -1  
      2.  发送消息
             msgsnd
                头文件:       #include <sys/ipc.h>
                                      #include <sys/msg.h>
                      #include <sys/types.h>

            函数原型:   int  msgsnd(int msgid,const void* msgp,size_t msgsz,int msgflg);
            函数功能:   创建或者获取消息队列
            函数参数:   msgid :       消息队列的标识符,
                     msgp          指向消息缓冲区的指针,是一个用户自定义的结构体
                                                   struct msgbuf
                           {
                               long    type;
                               char    text[SIZE];   
                           };
                           用于存放待发送的数据;
                                     msgsz:        发送的消息实际长度
                     msgflg :     一般设为0

            函数返回值:  成功  : 0
                         失败  : -1  
      3.  接收消息
           msgrcv
                头文件:       #include <sys/ipc.h>
                                      #include <sys/msg.h>
                      #include <sys/types.h>

            函数原型:   int  msgrcv(int msgid,const void* msgp,size_t msgsz,int mtype,int msgflg);
            函数功能:   创建或者获取消息队列
            函数参数:   msgid :       消息队列的标识符,
                     msgp          指向消息缓冲区的指针,是一个用户自定义的结构体
                                                   struct msgbuf
                           {
                               long    type;
                               char    text[SIZE];
                           };
                           用于存储接收到的消息数据
                                     msgsz:        待接收的消息实际长度
                     mtype:       待接收的消息类型
                     msgflg :     一般设为0

            函数返回值:  成功  : 返回实际接收到的消息长度
                         失败  : -1  
      4.  回收消息队列
                    msgctl
                 
                 头文件:       #include <sys/ipc.h>
                                           #include <sys/sem.h>
                                           #include <sys/types.h>

                 函数原型:    int msgctl(int msgid,int cmd,struct msqid_ds *buf);
                             函数功能:    对消息队列进行控制 
                 函数参数:   
                         msgid :       消息队列的描述符,  

                     cmd :        控制方式:                                   
                           IPC_STAT    获取状态信息
                               IPC_SET     设置状态信息  权限
                                                   IPC_RMID    回收消息队列
                 函数返回值:  成功  : 0
                              失败  : -1

    7.  信号(signal)

        信号在进程间通讯中是实现事件通知和进程控制;
    信号是系统在软件层,模拟实现中断自产生到被处理的整个流程。

        信号的操作:
     1.   发送信号
           1.1  系统发送
           1.2  进程给自身发送信号
                 raise
                头文件:       #include <signal.h>
                      #include <sys/types.h>

            函数原型:   int  raise(int signum);
            函数功能:   进程发送 signum 信号给自身进程
            函数参数:   signum :     信号编号,
            函数返回值:  成功  : 0
                         失败  : -1   错误码存放在 errno

           1.3  进程给其他进程发送信号  ***
                    kill
                        头文件:       #include <signal.h>
                      #include <sys/types.h>

            函数原型:   int  kill(pid_t pid,int signum);
            函数功能:   进程发送 signum 信号给pid进程
            函数参数:   pid:         指定的进程ID
                         signum :     信号编号,
            函数返回值:  成功  : 0
                         失败  : -1   错误码存放在 errno
           1.4  进程发送信号同时携带数据
                   sigqueue
                       头文件:        #include <signal.h>
                      #include <sys/types.h>

            函数原型:   int  sigqueue(pid_t pid ,int signum,const union sigval value);
            函数功能:   向pid进程发送signum 信号同时携带数据
            函数参数:   pid:         指定的进程ID
                         signum :     信号编号,
                         value:      信号携带的数据
                                  union sigval
                          {
                                                      int       sival_int;
                              void     *sival_ptr;
                          };
                        
            函数返回值:  成功  :  0
                         失败  : -1   错误码存放在 errno
     2.   信号处理
           1.1   忽略
           1.2   缺省
           1.3   捕捉处理
                     signal
                        头文件:       #include <signal.h>
                      #include <sys/types.h>

            函数原型:   sighandler_t  signal(int signum,sighandler_t handler);
            函数功能:   为signum 信号设置处理动作
            函数参数:   signum :     信号编号,
                         handler:    信号的处理动作
                                  1.  void handler(int s);    捕捉处理
                          2.  SIG_IGN                 忽略
                          3.  SIG_DFL                 默认
            函数返回值:  成功  : 返回上一个处理函数的地址
                         失败  : SIG_ERR   错误码存放在 errno
             sigaction
                        头文件:       #include <signal.h>
                      #include <sys/types.h>

            函数原型:   int sigaction(int signum,const struct sigaction* act,struct sigaction* oldact);
            函数功能:   为signum 信号设置处理动作
            函数参数:   signum :     信号编号,
                         act:        信号的处理动作
                     oldact :     [OUT] 旧的处理方式,如果不关心可设为NULL
                                  struct sigaction
                          {
                               void     (*sa_handler)(int);
                               void     (*sa_sigaction)(int, siginfo_t *, void *);
                               sigset_t   sa_mask;
                               int        sa_flags; //SA_SIGINFO
                               void     (*sa_restorer)(void);
                          };                                 
            函数返回值:  成功  : 0
                         失败  : -1   错误码存放在 errno
           1.4   屏蔽/阻塞
                 信号屏蔽: 临时不处理信号,但如果随后解除了屏蔽,信号还是要去响应处理的;
                        信号屏蔽不同于信号忽略

             sigprocmask
                头文件:       #include <signal.h>
                      #include <sys/types.h>

            函数原型:   int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
            函数功能:   屏蔽或解除屏蔽一个或者多个信号
            函数参数:   how:    操作方式
                                  1.  SIG_BLOCK    在已有屏蔽信号的基础上增加set中的屏蔽信号
                          2.  SIG_SETMASK  解除已有屏蔽信号,增加set中的屏蔽信号
                          3.  SIG_UNBLOCK  在已有屏蔽信号的基础上解除set中的屏蔽信号
                     set :     信号集合,
                                     oldset :  [OUT] 旧的屏蔽信号集合,如果不关心可设为NULL
            函数返回值:  成功  : 0
                         失败  : -1   错误码存放在 errno

   8. 定时器(timer) 
       
      定时器往往是应用于需要周期性处理的事务。
      定时器是Linux系统提供的一个软件资源。 

      启动定时器方法:

         alarm   
                    头文件:       #include <unistd.h>

            函数原型:   unsigned int alarm(unsigned int seconds);
            函数功能:   设置定时器
            函数参数:   seconds:    定时时长(以秒为单位)
            函数返回值:  成功  : 如果之前设置过定时器,返回上一个定时器遗留的时长
                                 否则返回为0
                         
     ualarm 
                    头文件:       #include <unistd.h>

            函数原型:   useconds_t ualarm(useconds_t usecs, useconds_t interval);
            函数功能:   设置定时器
            函数参数:   usecs:     初始定时时长 (以微秒为单位)
                         interval:  间隔时长     (以微秒为单位)
            函数返回值:  成功  : 如果之前设置过定时器,返回上一个定时器遗留的时长
                                 否则返回为0

            请注意:usecs 和  interval 不能超过 1 秒钟时长
 

  • 23
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值