进程间通信方法

内容由部分确实,等有空了再次个更新
进程间通信的方法

  • 管道
  • 共享内存
  • 消息队列
  • 信号量
  • 套接字

匿名管道

常用API

int pipe(int pipefd[2])
功能:创建一个匿名管道用于进程间通信
参数:int pipefd[2]这是一个传出参数
pipefd[0]:对应的是管道的写端
pipefd[1]:对应的是管道的读端
返回值:成功0,失败-1
管道是默认阻塞的:如果管道中没有数据,read阻塞,如果管道满了,write阻塞
匿名管道只能用于具有关系的进程之间的通信
代码

int main(){
	int pipfd[2];
	int ret=pipe(pipefd);
	if(ret==-1){
		perror("pipe");
		exit(0);
	}
	//创建子进程
	pid_t pid=fork();
	if(pid>0){
		printf("i am parent process,pid :%d\n",getpid());
		close(pipefd[1]);
		char buf[1024]={0};
		while(1){
			int len=read(pipfd[0],buf,sizeof(buf));
			printf(parent recv:%s,pid :%d\n",buf,getpid());
		}
	}else if(pid==0)
	{
		printf("i am child process,pid :%d\n",getpid());
		close(pipefd[0]);
		char buf[1024]={0};
		while(1){
			char*str="hello,i am child";
			write(pipfd[1],str,sizeof(str));
		}
	}
}

有名管道

int makefifo(char * pathname,mode_t mode)
参数:

  • pathname:管道名称的路径
  • mode:文件的权限和open的mode是一样的,是一个八进制的书

返回值:

  • 成功是返回0,失败时返回-1,并设置错误号
    代码

write.c

int main(){
	int ret=access("test",F_OK);
	if(ret==-1){
		printf("管道不存在,创建管道\n");
		 
		ret=mkfifo("test",0664);
		if(ret==-1){
			perror("mkfifo");
			exit(0);
		}
	}
	int fd=open("text",O_RDONLY);
	if(fd==-1){
		perror("open");
		exit(0);
	}
	for(int i=0;i<100;++i){
		char buf[1024]={0};
		sprintf(buf,"hello,%d\n",i);
		printf("write data %s\n",buf);
		write(fd,buf,sizeof(buf));
	}
	close(fd);
	return 0;
}

read.c

int main(){
	int fd=open("text",O_RDONLY);
	if(fd==-1){
		perror("open");
		exit(0);
	}
	while(1){
		char buf[1024]={0};
		int len=read(fd,buf,sizeof(buf));
		if(len==0){
			printf("写端断开连接了...\n");
		}
		printf("recv buf :%s\n",buf);
	}
	close(fd);
	return 0;
}

共享内存

共享内存是有效的IPC机制,因为它不涉及进程之间的任何数据传输。这种高效率带来的问题是,我们必须使用其他辅助收单来同步进程对共享内存的访问。否则会产生静态条件。因此共享内存通常和其他进程间通信一起使用
int semget(key_t key,size_t size,int shmflg)
功能

  • 创建一段新的共享内存,或者获取一段已经存在的共享内存

参数

  • key_t key:用于标志一段全局唯一的共享内存
  • size_t size:指定共享内存的大小,单位是字节,如果是创建新的共享内存,则size值必须被指定。如果是获取已经存在的共享内存,则可以把size设置为0
  • -int shmflg:与open相同

返回值

  • 成功时返回一个正整数,它是共享内存的标识符,错误是返回-1,并设置errno

void* shmat(int shm_id,const void*shm_addr,int shmflg)
功能

  • 共享内存被创建/获取之后,我们不能立即访问它,而是需要先将它关联到进程的地址空间中。

参数

  • int shm_id:由shmget调用返回的共享内存标识符。

  • const void*shm_addr:指定将共享内存关联到进程的哪块地址空间

      null:由操作系统选择,这是推荐的做法,以确保代码的可移植性
      非空 且 SHM_RND标志未被设置 : 
      非空 且 SHM_RND标志被设置 : 
    
  • int shmflg:

      SHM_RDONLY
      SHM_REMAP
      SHM_EXEC
    

int mmap(const void * shm_addr)

功能:

  • 使用完共享内存之后,我们也需要将它从进程地址空间中分离

int shmctl(int shm_id,int command,struct shmid_ds* buf)

参数

  • int shm_id:由shm_get返回的内存标识符

  • int command

     IPC_STAT
     IPC_SET
    

void* mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)

功能:

  • 将一个文件或设备的数据映射到内存中

参数

  • void* addr:NULL,有内核指定

  • size_t length:要映射的数据的长度,这个之不能为0,建议使用文件的长度,获取文件的长度:stat,lseek

  • int prot:对内存映射区的操作权限

     PROT_EXEC:可执行的权限
     PROT_READ:读权限
     PROT_WRITE:写权限
     PROT_NONE:没有权限
    
  • int flags

     MAP_SHARED:映射区的数据会自动和磁盘文件进行同步,进程间通信,必须要设置这个选型
     MAP_PRIVATE:不同步,内存映射区的数据改变了,对原来的文件不会修改,会重新创建一个新的文件
    
  • int fd:需要映射的那个文件的文件描述符

     通过open得到,open指定的权限不能和prot参数有冲突
    
  • off_t offset:偏移量,一般不用,0表示不便宜

void* munmap(void * addr,size_t length)

  • void * addr:要释放的内存首地址
  • size_t length:要释放内存的大小,要和mmap函数中的length一样

消息队列

消息队列是在两个进程之间传递二进制数据的一种简单有效方式。每个数据块都有一个特定的类型,接收方可以根据数据类型来选择地接收数据,而不一定像管道那样必须进行先进先出地方式接收

int msgget(key_t key,int msgflg)

  • key_t key:一个键值,用来标志一个全局唯一的消息队列
  • int msgflg
  • 成功时返回一个正整数,它时消息队列的标识符。msgget失败时返回-1,并设置errno

如果msgget用于创建消息队列,与之相关联的内核数据结构msqid_ds将被创建并初始化

int msgsnd(int msqid,const void*msg_ptr,size_t msg_sz,int msgflg)

功能

  • 把一条消息添加到消息队列中

参数

  • int msqid:由msgget调用返回的消息队列标识符

  • const void*msg_ptr:指向一个准备发送的消息,消息必须被定义为如下类型

     struct msgbuf{
     	long mtype;
     	char mtext[512]
     } 
    
  • size_t msg_sz:消息队列数据部分的长度,这个长度可以为0,表示没有消息队列

  • int msgflg:控制msgsnd行为,通常仅支持IPC_NOWAIT标志,即以阻塞的方式发送消息。默认情况下,发送消息时如果消息队列满了,则msgsnd将阻塞。若IPC_NOWAIT标志被指定。则msgsnd将立即返回并设置errno为EAGAIN

int msgrcv(int msqid,void*msg_ptr,size_t msg_sz,long int msgtytpe,int msgflg)

功能

  • 从消息队列中获取消息

参数

  • int msqid:由msgget调用返回的消息队列标识符

  • void*msg_ptr:用于存储接收消息

  • size_t msg_sz:消息队列数据部分的长度

  • long int msgtytpe

     msgtype等于0。读取消息队列中的第一个消息
     msgtype大于0。读取消息队列中第一个类型为msgtype的消息
     msgtype小于0。读取消息队列中第一个类型值比msgtype的绝对值小的消息
    
  • int msgflg:控制msgrcv行为,它可以是如下标志的按位或

     IPC_NOWAIT:
     IPC_EXCEPT:
     IPC_NOERROR:
    

int msgctl(int msqid,int command,struct msqid_ds*buf)

信号量

int msgctl(int msqid,int command,struct msqid_ds*buf)

功能:

-创建一个新的信号量集,或者获取一个 已经存在的信号量集

  • int msqid:用来标记一个全局的信号量集,就像头文件全局唯一地标识一个文件一样。通过信号量通信的进程需要使用相同的键值来创建/获取该信号量
  • int command:指定要创建/获取的信号集中信号量的数目。如果是创建信号量。则该值必须被指定;如果是获取已经存在的信号量。则可以把它设置为0
  • struct msqid_ds*buf:低端9个比特是该信号量的权限,其格式和含义都与open的mode参数相同。此外,它还可以和IPC_CREAT标志做按位”或“运算以创建新的信号量集。此时即使信号量已经存在,senget也不会报错

返回值:

  • 成功时返回一个正整数值,它是信号量的标识符;失败时返回-1,并设置errno

int semop(int sem_id,struct sembuf* semops,size_t num_sem_ops)
参数

  • int sem_id:由semget调用返回的信号量标识符,用以指定被操作的目标信号量集
  • struct sembuf* semops:指向一个sembuf结构体类型的数组。sembuf结构体的定义如下
struct sembf
{
	unsigned short int sem_num;
	short int sem_op;
	short int sem_flg;
}
sem_num表示信号集中信号量的编号,0表示信号量集中的第一个信号量
sem_op成员指定操作类型,可以选值为正整数,0和负数
sem_flg可选值为IPC_NOWAIT,SEM_UNDO
SEM_NOWAIT的含义是,无论信号操作是否成功,semop调用都立即返回
SEM_UNDO的含义是,当前进程退出时取消正在进行的semop操作。
  • size_t num_sem_ops:指定要执行的操作个数

int semctl(int sem_id,int sem_num,int command,...)

功能

  • 对信号量进行直接控制

参数

  • int sem_id:由sem_get调用返回的信号量集标志符,用以指定被操作的信号量集

  • int sem_num:指定被操作的信号量在信号集中的标号

  • int command:要执行的命令

      IPC_STAT
      IPC_SET
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值