Linux10,11进程间通信(管道,信号量,共享内存,消息队列,套接字(未讲))

进程间通信命令:

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才可以拿到。

5.套接字(后面讲)

猜你喜欢

转载自blog.csdn.net/sunshinecandy/article/details/88765932
今日推荐