Linux 进程间通信

管道
半双工具有固定的读写端
只能用于父子或兄弟进程的通信
可用read write等函数读写,但不属于文件系统,只存在与内存中。

原型

#include<unistd.h>
int pipe(int fd[2]);//返回0则成功,-1失败

fd[0]为读打开,fd[1]为写打开

#include<unistd.h>
#include<stdio.h>
int main(){
	int fd[2];
	int pid;
	char buf[128];
	if(pipe(fd) == -1){
		printf("creat pipe failed\n");
	}
	pid=fork();
	if(pid<0){
		printf("child failed\n");
	}
	else if(pid>0){
		printf("this is father\n");
		close(fd[0]);
		write(fd[1],"hello",5);
	}else{printf("this is child\n");
		close(fd[1])
		read(fd[0],buf,128);
		printf("read from father:%s\n",buf);
	}	
	return 0;
}

FIFO命名管道
可以在无关进程(非父子兄弟)间交换数据
有路径名与之关联
原型#include<sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);`
read

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
int main(){
	char buf[128]={0};
	if((mkfifo("./file",0600)==-1)&& errno!=EEXIST){
		printf("mkfifo failed\n");
		perror("why");
		}
	int fd = open("./file",O_RDONLY);
	printf("open success\n");
	
	int nread = read(fd,buf,128);
	printf("read %d byte from fifo:%s",nread,buf);
	close(fd);

	return 0;
}

write

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
int main(){
	cahr *str="msg from fifo";
	int fd=open("./file",O_WRONLY);
	printf("write open success\n");
	write(fd,str,strlen(str));
	close(fd);
	return 0;
	}

消息队列
消息队列是消息的链表,消息队列由一个标识符标识。
消息队列面向记录的,消息具有特定的格式以及特定的优先级
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定以先进先出的次序读取,也可以按消息的类型读取。
API

#include<sys/msg.h>
int msgget(Key_t key,int flag);
//创建或打开消息队列,成功返回队列号,失败返回-1。
int msgsnd(int msqid,const void *ptr,size_t size,int flag);
//添加消息,成功返回0,失败-1
int msgrcv(int sgqid,void *ptr,size_t size,long type,int flag);
//读取消息,成功返回数据长度,失败-1
int msgctl(int msqid,int cmd,struct msqid_ds *buf);
//控制消息队列成功返回0,失败-1

msgget创建消息队列:
1 如果没有与键值key相对应的消息队列,并且flag中包含了IPC_CREAT标志位。
2 key参数为IPC_PRIVATE

type参数:
type==0,返回队列第一个消息
type> 0,返回对列消息类型为type的第一个消息
type< 0,返回队列中消息类型小与或等于type绝对值的消息,如果有多个,取类型值最小的消息
type值非0时用于以非先进先出次序读消息。也可以把type看做优先级的权值
read

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
struct msgbuf{
	long mtype;
	cahr mtext[128];
};
int main()
{
	struct msgbuf readbuf;

	int msgID=msgget(0x1234,IPC_CREAT|0777);
	if(msgID==-1){
		printf("msg failed\n");
	}
	msgrcv(msgID,&readbuf,sizeof(readbuf.mtext),888,0);
	printf("read from readbuf %s\n",readbuf.mtext);
	return 0;
}

send

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
struct msgbuf{
	long mtype;
	cahr mtext[128];
};
int main()
{
	struct msgbuf senbuf={888,"this is msg send"};

	int msgID=msgget(0x1234,IPC_CREAT|0777);
	if(msgID==-1){
		printf("msg failed\n");
	}
	msgsnd(msgID,&sendbuf,strlen(sendbuf.mtext),0);//0表示非租塞的发
	return 0;
}

key 也可以用ftok生成`

key_t key;
key= ftok(".",'z');
//用索引节点和 ID配合生成key

共享内存

#include<sys/shm.h>
int shmget(key_t key,size_t,int flag);
//创建或获取一个共享内存,成功返回ID,失败-1
viod *shmat(int shm_id,const void *addr,int flag);
//连接共享内存到当前进程的地址空间,成功返回指向共享内存的指针,失败-1
int shmdt(void *addr);
//断开与共享内存的相关信息,成功返回0,失败返回-1
int shmctl(int shm_id,int cmd,struct shmid_ds *buf);
//控制共享内存的相关信息,成功返回0,失败返回-1

shmget创建一段共享内存,必须指定其size;如果引用存在的size为0。flag可以用默认为0
创建成功后不会被任何进程访问,必须使用过shmat连接共享内存到当前进程的地址空间呢,连接成功后把内存区对象调用到进程的地址空间,随后可像本地空间一样访问
shmctl可以对内存执行多种操作,根据cmd执行相应操作,常用IPC_RMID(从系统中删除共享内存)
write

#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
	int shmid;
	key_t key;
	key = ftok(".",1);
	char *shmaddr;

	shmid =shmget(key,1024*4,IPC_CREAT|0666);
	if(shmid == -1){
		printf("shmget faled");
		exit(-1);
	}
	shmaddr=shmat(shmid,0,0);
	printf("ok");
	strcpy(shmaddr,"hello");
	sleep(1);
	shmdt(shmaddr);
	shmctl(shmid,IPC_RMID,0);
	return 0;
}

read

#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
	int shmid;
	key_t key;
	key = ftok(".",1);
	char *shmaddr;

	shmid =shmget(key,1024*4,0);
	if(shmid == -1){
		printf("shmget faled");
		exit(-1);
	}
	shmaddr=shmat(shmid,0,0);
	printf("ok\n");
	printf("data is %s\n",shmaddr);

	shmdt(shmaddr);

	return 0;
}

可用ipcs -m查看共享内存
ipcrm -m ID删除共享内存
信号
每一个信号都有一个名字和编号,,这些名字都以SIG开头
信号定义在signal.h中,信号明定以为正整数。
可以用kill -l 来查看信号的名字及序号,信号是从1开始编号

信号的处理
信号处理的三种:忽略,捕获和默认动作
忽略:大多数可以忽略,除了SIGKILL 和SIGSTOP
捕捉:告诉内核用户希望处理某种信号。说白了就是写一个信号处理函数,当信号产生时,由内核来调用用户自定义的函数以此实现某种信号处理
默认:可用man 7 signal来查看具体定义

#include<signal.h>
#include<stdio.h>
void handler(int signum){
	printf("get signum=%d\n",signum);//signum 可用kill -l查看
	printf("never qiut\n");
}
int main(){
	signal(SIGINT,handler);//信号注册(信号,函数名)
	while(1);
	return 0;
}

kill -signum xxxx(进程)
给xxxx进程发送某个值为signum的信号
signal(SIGINT,SIG_IGN);表示忽略SIGINT信号
携带信息的函数sigaction详解
信号量
用于实现进程见得互斥与同步,而不是存储数据
若要进程间数据传递需要共享内存
基于PV操作,程序对信号量的操作是原子操作
支持信号量组

#include<sys/sem.h>
int smget(key_t,int num_sems,int sem_flags);
//创建或获取一个信号量组,成功返回ID失败-1(num_sem为信号量个数)
int semop(int semid,struct sembuf semoparray[],size_t numops);
//改变信号量的值,成功返回0,失败-1
int semctl(int semid,int sem_num,int cmd,...);
//控制信号量相关信息
#include<sys/sem.h>
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/types.h>
union semun{
		int val;
		struct semid_ds *buf;
		unsigned short *array;
		struct seminfo *_buf;
	};
void pgetkey(int id){
	struct sembuf set;
	set.sem_num=0;
	set.sem_op=-1;
	set.sem_flag=SEM_UNDO;
	semop(id,&set,1);
}

void vputkey(int id){
	struct sembuf set;
	set.sem_num=0;
	set.sem_op=1;
	set.sem_flag=SEM_UNDO;
	semop(id,&set,1);
}

int main(int argc,char const *argv[]){
	key_t key;
	int semid;
	ket=ftok(".",2);
	semget(key,1,IPC_CREAT|0666);
	union semun initsem;
	initsem.val =0;
	semtcl(semid,0,SETVAL,initsem);//初始化信号量(操作第0个信号量,SETVAL设置信号量的值为inisem.val)

	int pid=fork();
	if(pid>0){
		pgetkey(semid);//拿锁
		printf("this is father\n");
		 vputkey(semid);//放锁
	}
	 else if(pid==0){
	 	
		printf("whis is child\n");
		 vputkey(semid);
	}else{
		printf("failed\n";
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值