linux 大复习 进程2 通信
进程间通信方式
1.匿名管道 父子进程之间进行通信 ;
需要两个文件文件描述符 fd[2]
小读 大写
状态: 1.写关了 读 EOF
2.没有数据读 ,阻塞
3.读取关了,写会导致管道破裂
4.没有地方写,阻塞
通过fcntl 控制·管道属性,fpathconf 测试管道缓冲区大小
#include<stdio.h> #include<string.h> #include<stdlib.h> #include <unistd.h> #include<sys/wait.h> /* int pipe(int pipefd[2]); #include <fcntl.h> #include <unistd.h> int pipe2(int pipefd[2], int flags); */ #define MSG "hello pipe\n" int main() { int fd[2]; if(pipe(fd)==-1) { perror("pipe createt errno"); exit(0); } pid_t pid =fork(); if(pid==0) { //子进程 关闭读方向 close(fd[0]); write(fd[1],MSG,strlen(MSG)); /* while(1) { write(fd[1],MSG,strlen(MSG)); // sleep(1); } */ } else if(pid>0) { char buf[1024]; close(fd[1]); while(1) { size_t tt = read(fd[0],buf,sizeof(buf)); write(STDOUT_FILENO,buf,tt); } if(wait(NULL)==-1) { perror("the son want to live more \n"); exit(0); } } else { perror("the fork errno"); exit(0); } return 0; }
2.有名管道 通过mkfifo 创建管道文件
状态: 打开注意:先写打开才能正常都去打开 否则会产生阻塞
设置管道为阻塞 状态:1.没有数据 读 阻塞
2.写操作 会产生拆开数据流,进行写入
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* i #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); */ #define MSG "hello pipe\n" int main(int argc ,char ** argv) { int fd = mkfifo(argv[1],0664); if(fd==-1) { perror("mkfifo errno :"); } fd =open(argv[1],O_WRONLY); while(1) write(fd,MSG,strlen(MSG)); perror("mkfifo errno :"); return 0; }
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* i #include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); */ #define MSG "hello pipe\n" int main(int argc ,char ** argv) { char buf[1024]; int fd = open(argv[1],O_RDONLY); int tt = read(fd,buf,sizeof(buf)); write(STDOUT_FILENO,buf,tt); perror("mkfifo errno :"); close (fd); return 0; }
3.消息队列
内核对象链表状态 由消息队列标识符表示
有两个标准1.system V 和 posix
首先
1号消息队列 msgget 可以创建 两种消息队列 私有 或者公共 ipcs
2号消息队列为了移植 但是列表名字必须以 / 开始 并且需要挂在 才可见
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> typedef struct msgbuf { long mtype; char mtext[1024*10]; }sz ; int main(int argc,char **argv) { key_t key = ftok("/home", 123); int msqid =msgget(key,0666|IPC_EXCL); if(msqid==-1) { perror("msgget errno "); exit(0); } char msgp[1024]; //等于 0 第一条 // >0 返回等于的消息 //<0 返回第一个绝对值小于等于 的消息 ssize_t ret = msgrcv( msqid, msgp,sizeof(msgp), 0, IPC_NOWAIT); if(ret==-1) { perror("mshrcv errno"); exit(0); } printf("%s \n",((struct msgbuf*)msgp)->mtext); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <mqueue.h> /* struct mq_attr { long mq_flags; long mq_maxmsg; long mq_msgsize; long mq_curmsgs; }; */ int main() { // printf("%d\n",mq_unlink("/tt")); mqd_t mqdes = mq_open("/tt", O_RDWR|O_CREAT|O_EXCL); //mqd_t mqdes = mq_open("/tt", O_WRONLY); if(mqdes ==-1) { perror("mqopen errno "); exit(0); } printf("%d\n",mqdes); char buf[]="hello world \n "; if(mq_send(mqdes, buf,sizeof(buf) , 1)==-1) { perror("mqopen errno "); exit(0); } struct mq_attr attr; memset(&attr,0,sizeof(attr)); if(mq_getattr(mqdes, &attr)==-1) { perror("mq_getattr errno "); exit(0); } printf("mq_flags : %ld\t mq_maxmsg : %ld\t mq_msgsize : %ld\t mq_curmsgs : %ld\n" ,attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs); printf("%d\n",mq_close( mqdes)); return 0; }
4.共享内存映射 mmap munmap
产生共享内存映射,选择模式 共享内存 私人映射
共享内存 进行通信 ,私人映射
1、用于进程间通信时,一般设计成结构体,来传输通信的数据
2、进程间通信的文件,应该设计成临时文件(即创建文件,使用文件,删除文件)
3、 当报总线错误时,优先查看共享文件是否有存储空间
#include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd = open("a", O_RDWR); char * ps = mmap(NULL,120, PROT_WRITE, MAP_SHARED, fd, 0); if(ps==NULL) { perror("mmap errno"); exit(0); } for(int i=0;i<10;i++) ps[i]='h'; //write(STDOUT_FILENO,ps,off); munmap(ps,120); return 0; }
5.信号量 你需要信号量进行开始 或者阻塞
使用范围 进行 PV 操作
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <semaphore.h> #include <errno.h> int sem_create(key_t key) { int semid = 0; semid = semget( key, 1 , 0666|IPC_CREAT | IPC_EXCL); if(semid ==-1) { if(errno ==EEXIST) { printf("the sem has existed \n"); semid = semget( key, 1 ,0666); } } return semid; } union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; int sem_setval(int semid,int val ) { int ret =0; union semun su; su.val =val; ret = semctl(semid, 0 , SETVAL, su); return ret; } int sem_getval(int semid ) { union semun su; semctl(semid, 0, GETVAL, su); return su.val; } /* struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; }; */ int sem_p(int semid) { struct sembuf sops={0,-1,0/* IPC_NOWAIT 阻塞 SEM_UNDO 回退 */}; int ret = semop( semid, &sops, 1); if(ret==-1) { perror("sem_p errno"); exit(0); } return 0; } int sem_v(int semid) { struct sembuf sops={0,1,0}; int ret = semop( semid, &sops, 1); if(ret==-1) { perror("sem_p errno"); exit(0); } return 0; } int main() { int ret; key_t key = ftok("/tt", 1); int semid =sem_create(key); if(semid <0 ) { perror("sen_create errno "); exit(0); } //几个信号量 才能运转起来 //设置信号量数值 ret = sem_setval(semid,0); ret = sem_getval(semid ); printf("sem_getval %d \n",ret); //加减锁 sem_p(semid); printf("hello sem \n"); sem_v(semid); printf("semid %d \n",semid); }
不摸着石头过河,难道要在温柔乡睡到天昏地暗。