管道
半双工具有固定的读写端
只能用于父子或兄弟进程的通信
可用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;
}