进程间通信命令:
ipcs可以看进程间的通信
-s看信号量-q消息队列-m共享内存
1.管道
1.1用法
管道有同步,在内存中使用方便。
有名管道,mkfifo fifo创建管道
无名管道。(在父子进程间使用)
1.2面试问题
1.管道是半双工,对讲机(半双工,同一时刻只能发或收)
单工(只能接受或发送)
全双工(吵架)
2.区别:任意两个进程
无名:只在父子进程间通讯。
3.管道在内存上存着。写入管道的文件在内存中
写端彻底关闭,读端read返回值为0;
读关闭,写端会引发异常,SIGPIPE信号。
信号量:pv操作,临界区,临界资源。
1.3代码实现
1.3.1a.c(写数据)
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<assert.h>
5 #include<fcntl.h>
6 #include<unistd.h>
7 int main()
8 {
9 int fd=open("./fifo",O_WRONLY);
10 assert(fd!=-1);
11
12 printf("fd=%d\n",fd);
13 while(1)
14 {
15 printf("input:\n");
16 char buff[128]={0};
17 fgets(buff,128,stdin);
18 if(strncmp(buff,"end",3)==0)
19 {
20 break;
21 }
22 write(fd,buff,strlen(buff));//写数据
23 }
24
25 close(fd);
26 //exit(0);
27 }
1.3.2 b.c(读数据)
#include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<assert.h>
5 #include<fcntl.h>
6 #include<unistd.h>
7 int main()
8 {
9
10 int fd=open("./fifo",O_RDONLY);//打开管道
11 assert(fd!=-1);
12
13 printf("fd=%d\n",fd);
14
15 while(1)
16 {
17 char buff[128]={0};
18 int n=read(fd,buff,127);//读数据
19 if(n==0)
20 {
21
22 break;
23 }
24 printf("n=%d,buff=%s\n",n,buff);
25 }
26
27 close(fd);
28 //exit(0);
29 }
结果:a中写入的数据b读出来,输入end后a,b同时结束。
2.信号量
2.1临界资源,临界区
1.临界资源:同一时刻只允许一个进程(线程)访问的资源
临界区:访问临界资源的代码段。
2.Ulimit -a(查看限制信息)
Ulimit -代号 可以改大小(不能永久改变,只能临时改变。)
3.信号量:特殊的变量,值可以改变,对信号量加一减一的操作都是原子操作,p操作对信号量的值进行原子减一,p代表申请资源。信号量值为0的时候则p操作阻塞,
v操作是对信号量的原子加一,不会阻塞。V代表释放资源,
4.作用:同步进程
5.二值信号量:0,1
6.计数信号量:有个数值计数用值大于一的信号量
接口:
semget()创建一个信号量
semctl()信号量赋值,
7…ipcs可以看进程间的通信
-s看信号量-q消息队列-m共享内存
ipcsrm - s +id删除信号量
getconf LONG_BIT看Linux是多少位的(32位)
IPC(进程间通信)
2.2代码实现
2.2.1a.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include"sem.h"
7 int main ()
8 {
9 sem_init();
10 int i=0;
11 for(;i<5;i++)
12 {
13 sem_p();
14 printf("A");
15 fflush(stdout);
16
17 int n=rand()%3;
18 sleep(n);
19
20
21 printf("A");
22 fflush(stdout);
23 sem_v();//v操作
24
25 n=rand()%3;
26 sleep(n);
27 }
28
29 }
2.2.2b.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include"sem.h"
7 int main ()
8 {
9 sem_init();
10 int i=0;
11 for(;i<5;i++)
12 {
13 sem_p();
14 printf("B");
15 fflush(stdout);
16
17 int n=rand()%3;
18 sleep(n);
19
20
21 printf("B");
22 fflush(stdout);
23 sem_v();
24
25 n=rand()%3;
26 sleep(n);
27 }
28 sleep(10);
29 sem_destroy();
30 exit(0);
31 }
2.2.3sem.c
1 #include"sem.h"
2
3 static int semid=-1;
4 void sem_init()
5 {
6 semid=semget((key_t)1234,1,IPC_CREAT |IPC_EXCL |0600);//尝试全新创建一个信号量
7 if(semid==-1)
8 {
9 semid=semget((key_t)1234,1,IPC_CREAT|0600);//获取已有的一个信号量
10 //if()
11 if(semid==-1)
12 {
13 perror("semget error");
14 return;
15 }
16 }
17 else
18 {
19 union semun a;
20 a.val=1;
21 if(semctl(semid,0,SETVAL,a)==-1)//信号量赋初值
22 {
23 perror("semctl error");
24
25 }
26
27 }
28 }
29 void sem_p()
30 {
31 struct sembuf buf;
32 buf.sem_num=0;//
33 buf.sem_op=-1;//p操作
34 buf.sem_flg=SEM_UNDO;
35
36 if(semop(semid,&buf,1)==-1)
37 {
38 perror("semop p error");
39 }
40
41 }
42 void sem_v()
43 {
44
45 struct sembuf buf;
46 buf.sem_num=0;//
47 buf.sem_op=1;//p操作
48 buf.sem_flg=SEM_UNDO;
49
50 if(semop(semid,&buf,1)==-1)
51 {
52 perror("semop v error");
53 }
54 }
55 void sem_destroy()
56 {
57 if(semctl(semid,0,IPC_RMID)==-1)
58 {
59 perror("semctl error");
60 }
61
62 }
2.2.4sem.h
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<string.h>
5 #include<sys/sem.h>
6 #include<unistd.h>
7 union semun
8 {
9 int val;
10 };
11
12 void sem_init();
13 void sem_p();
14 void sem_v();
15 void sem_destroy();
16
结果:
a,b两个进程访问同一内存,打印的A和B成对出现。
3.共享内存
3.1原理
1.申请一块空间作为共享内存,2.将将共享内存映射到多个进程的地址中)
接口:
shmget()//创建
Shmat()//映射到进程地址空间
Shmdt()//断开映射
Shmctl()//删除共享内存
1.确定信号量数量,由控制点决定
2.赋初值
3.Pv操作同步
4.扩展:广义共享内存实现几种方式《内核代码分析》
3.2代码实现
3.2.1a.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<sys/shm.h>
6 #include<string.h>
7 #include"sem.h"
8 int main ()
9 {
10 int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//名字,大小,权限
11 assert(shmid!=-1);
12
13 char* s=(char *)shmat(shmid,NULL,0);//null不指定映射到程序中的逻辑地址,0标志位
14 sem_init();
15 while(1)
16 {
17 char buff[128]={0};
18 printf("input:\n");
19 fgets(buff,128,stdin);
20
21 sem_p(0);//first signal ps1
22 strcpy(s,buff);
23 sem_v(1);//vs2
24 if(strncmp(buff,"end",3)==0)
25 {
26 break;
27 }
28 }
29
30
31 // sleep(5);
32 shmdt(s);//断开映射
33 //if( shmctl(shmid,IPC_RMID,NULL)==-1)
34 // {
35 //perror("shmctl error");
36 // }//移除共享内存空间
37 exit(0);
38 }
3.2.2b.c
#include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<sys/shm.h>
6 #include<string.h>
7 #include"sem.h"
8 int main ()
9 {
10 int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//名字,大小,权限
11 assert(shmid!=-1);
12
13 char* s=(char *)shmat(shmid,NULL,0);//null不指定映射到程序中的逻辑地址,0标志位
14 assert(s!=NULL);
15 sem_init();
16 while(1)
17 {
18 sem_p(1);//ps2
19 if(strncmp(s,"end",3)==0)
20 {
21 break;
22 }
23 printf("s=%s\n",s);
24 sem_v(0);//vs1
25 }
26 shmdt(s);
27 sem_destroy();
28
29 shmdt(s);//断开映射
30 if( shmctl(shmid,IPC_RMID,NULL)==-1)
31 {
32 perror("shmctl error");
33 }//移除共享内存空间
34 exit(0);
35 }
3.2.3sem.c
1 #include"sem.h"
2 #define MAX_SEM 2
3 static int semid=-1;
4
5 void sem_init()
6 {
7 //creat signal
8 semid=semget((key_t)1234,MAX_SEM,IPC_CREAT|IPC_EXCL|0600);
9 if(semid==-1)
10 {
11 semid=semget((key_t)1234,MAX_SEM,0600);
12 if(semid==-1)
13 {
14 perror("semget error");
15 return ;
16 }
17
18 }
19 else
20 {
21 union semun a;
22 int arr[MAX_SEM]={1,0};
23 int i=0;
24 for(;i<MAX_SEM;i++)
25 {
26 a.val=arr[i];
27 if(semctl(semid,i,SETVAL,a)==-1)
28 {
29 perror("semctl error");
30 }
31 }
32 }
33
34 }
35 void sem_p(int index)
36 {
37 if(index<0||index>= MAX_SEM)
38 {
39 perror("p argc error \n");
40 return;
41 }
42
43 struct sembuf buf;
44 buf.sem_num=index;
45 buf.sem_op=-1;//p
46 buf.sem_flg=SEM_UNDO;
47
48 if( semop(semid,&buf,1)==-1)
49 {
50 perror("semop p error");
51 }
52
53 }
54 void sem_v(int index)
55 {
56 if(index<0||index>= MAX_SEM)
57 {
58 perror("v argc error \n");
59 return;
60 }
61
62 struct sembuf buf;
62 struct sembuf buf;
63 buf.sem_num=index;
64 buf.sem_op=1;//v
65 buf.sem_flg=SEM_UNDO;
66
67 if( semop(semid,&buf,1)==-1)
68 {
69 perror("semop v error");
70 }
71
72 }
73 void sem_destroy()
74 {
75 if( semctl(semid,0,IPC_RMID)==-1)
76 {
77 perror("semctl error");
78 }
79 }
3.2.4sem.h
1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #include<assert.h>
5 #include<sys/sem.h>
6 #include<unistd.h>
7 union semun
8 {
9 int val;
10 };
11 void sem_init();
12 void sem_p(int index);
13 void sem_v(int index);
14 void sem_destroy();
结果:
在a中输入b中打印buff中的数据,a输入了b才打印,输入end后a,b同时结束。
4.消息队列
4.1接口函数
msgget()创建消息队列
4.2代码实现
4.2.1 a.c(放入消息)
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<string.h>
5 #include<unistd.h>
6 #include<sys/msg.h>
7 struct mess
8 {
9 long type;
10 char buff[32];
11 };
12 int main()
13 {
14
15 int msgid=msgget((key_t)1234,IPC_CREAT|0600);
16 assert(msgid!=-1);
17
18 struct mess dt;
19 dt.type=1;
20 strcpy(dt.buff,"hello1");
21
22 msgsnd(msgid,(void *)&dt,32,0);
23 }
4.2.2b.c(获取消息)
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<string.h>
5 #include<unistd.h>
6 #include<sys/msg.h>
7 struct mess
8 {
9 long type;
10 char buff[32];
11 };
12 int main()
13 {
14
15 int msgid=msgget((key_t)1234,IPC_CREAT|0600);
16 assert(msgid!=-1);
17
18 struct mess dt;
19
20 msgrcv(msgid,(void *)&dt,32,1,0);//把1变为0后代表不区分消息类型,从上往下一次获取。
21 printf("dt.buff==%s\n",dt.buff);
22
23 exit(0);
24 }
结果:
a放入消息队列中消息后,b才可以拿到。