进程间的通信方式

一、管道

  1. 局限性
    (1)半双工。
    (2)只能在具有公共祖先的两个进程间通信。
  2. 创建
#include <unistd.h>
int pip(int fd[2]);

参数fd返回两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。fd[1]写入,fd[0]读出。
3. 经由父进程向子进程传送数据的例子

#include "apue.h"
int main()
{
    int n;
    int fd[2];
    pid_t pid;
    char line[MAXLINE];
    if(pipe(fd)<0)
        printf("pipe error");
    if((pipe(fd)==fork())<0)
        printf("fork error");
    else if(pid>0)//parent
    { 
        close(fd[0]);
        write(fd[1],"hello world\n",12);
    }
    else//child
    {
        close(fd[1]);
        n=read(fd[0],line,MAXLINE);
        write(STDOUT_FILENO,line,n);
        printf("%s",line);
    }
    exit(0);
}
  1. 函数popen和pclose
#include <stdio.h>
FILE *popen(const char *cmdstring,const char *type);
int pclose(FILE *fp);

创建一个管道,fork一个子进程,关闭未使用的管道,执行一个shell命令,然后等待命令终止。

二、FIFO

  1. 不相关的进程间交换数据(命名的管道)
  2. 创建
#include <sys/stat.h>
int mkfifo(const char *path,mode_t mode);
int mkfifoat(int fd,const char *path,mode_t mode);

path为绝对路径,fd参数被忽略,mkfifo与mkfifoat相似;path相对路径,fd是一个打开目录的有效文件描述符;path相对路径,且fp有特殊值AT_FDCWD,则路径名以当前目录开始,mkfifo与mkfifoat相似。
3. 用途
shell命令使用FIFO将数据从一条管道传送到另一条时,无需创建中间临时文件;客户进程-服务器进程应用程序中,FIFO用作汇聚点,在客户进程和服务器进程二者之间传递数据。

三、 消息队列

  1. 消息的链接表,存储在内核中,由消息队列标识符标识。
  2. 创建
#include <sys/msg.h>
int msgget(key_t key,int flag);//打开一个现有队列或是创建一个新队列
int msgsnd(int msqid,const void*ptr,size_t nbytes,int flag);//将数据放入到消息队列中,消息总是放在队列尾端
ssize_t msgrcv(int msqid,void *ptr,size_t nbytes,long type,int flag);//从消息队列中取用消息

ptr参数指向一个长整型数(其中存储的是返回的消息类型),其后面是存储实际消息数据的缓冲区。nbytes指定了数据缓冲区的长度。type=0,返回队列中的第一个消息;type>0,返回队列中消息类型为type的第一个消息;type<0,=,返回队列中消息类型值小于等于type绝对值的消息,如果这种消息有多个,则取类型值最小的。

四、信号量

信号量与前面的IPC机构(管道、FIFO以及消息队列)不同,它是一个计数器,用于为多个进程提供对共享数据对象的访问。
1. 为获得资源进程的操作:测试控制所需资源的信号量;若该资源的信号量的值为正,则可以使用该资源,获得资源使用权后,信号量的值会减1; 若信号量的值为0,则进程进入休眠状态,等到信号量的值大于0时才被唤醒。
2. 内核为信号量维护的semid_ds结构

struct semid_ds{
      struct ipc_perm sem_perm;//权限结构
      unsigned short sem_nsems;//of semaphores in set
      time_t sem_otime;//last-semop() time
      time_t sem_ctime;//last-change time
};
  1. 每一个信号量有一个无名结构表示
struct{
    unsigned short semval;//semaphore value,always>=0
    pid_t sempid;//pid for last operator
    unsigned short semncnt;//processes awaiting semval>curval;
    unsigned short semzcnt;//processes awaiting semval==0
};
  1. 创建
#include <sys/sem.h>
int semget(key_t key,int nsems,int flag);

若成功返回一个信号量的ID,key为信号量对象的外部名,其中nsems表示集合中的信号量数。

五、共享存储

允许两个或是多个进程共享一个给定的存储区。数据不需要在客户和服务器进程间复制,所以这是最快的一种IPC。使用共享存储需要知道,在多个进程之间同步的访问一个给定的存储区。
1. 共享存储的结构

struct{
    struct ipc_perm shm_perm;//规定权限和所有者
    size_t shm_segsz;//size of segment in bytes
    pid_t shm_lpid;//pid of last shmop()
    pid_t shm_cpid;//pid of creator
    shmatt_t shm_nattch;//number of current attaches
    time_t shm_atime;//last-attach time
    time_t shm_dtime;//last-detach time
    time_t shm_ctime;//last-change time
};
  1. 创建
#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);

获得一个存储标识符,在创建新的IPC结构时,如果key是IPC_PRIVATE或者和当前某种类型的IPC结构无关,则需要指明flag的IPC_CREAT标志位。为了引用一个现有的队列,key必须等于队列创建时指明的key的值,且IPC_CREAT必须不被指明。msgget和semget也是这样的。
3. 位置:共享存储段紧靠在栈之下
在基于Intel的linux系统上的存储区布局图

六、信号量、记录锁和互斥量的比较

  1. 信号量:先创建一个包含该信号量的集合,然后再将该信号量初始化为1。分配资源,以sem_op为-1调用semop;释放资源,以sem_op为1调用semop。对每个操作都指定SEM_UNDO,以处理在为释放资源条件下进程终止的情况。
  2. 记录锁:先创建一个空文件,且用该文件的第一个字节作为锁。分配资源,先对该字节获得一个写锁;释放资源,则对该字节解锁。记录锁的性质确保了当一个锁的持有者进程终止时,内核会自动释放该锁。
  3. 互斥信号量:需要所有的进程将相同的文件映射到他们的地址空间里,且使用PTHREAD_PROCESS_SHARED互斥量属性在文件的相同偏移处初始化互斥量。分配资源,对互斥量加锁;释放资源,解锁互斥量。如果一个进程没有释放互斥量而终止,恢复很困难,除非是用鲁棒性的互斥量。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值