进程间的通信

学习笔记(四)之进程之间的通信

进程间通信7种:

一.unix同寿的老三件:
管道:是一种半双工机制,在unix中大小为64k,存在于内核

1.无名管道:只能用于有亲缘关系的进程之间,本质通过文件描述符操作
pipe
int pipe(int pipefd[2]);
功能:在内核创建无名管道,并返回操作该管道的两个文件描述符
参数:1.文件描述符数组 (创建同类型数组,将数组首地址填入) fd[0]得到的是管道的读端 fd[1]得到的是管道的写端
返回值:成功返回0,失败返回-1,并设置errno号
注:
文件描述符不用的及时关闭:
1.文件描述符是有限的资源
2.操作不该使用的文件描述符有可能会导致误操作

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <strings.h>
 5 #include <string.h>
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     pid_t pid;
10 
11     int ret = 0;
12     int fd[2];
13     ret = pipe(fd);
14     if(ret < 0)
15     {
16         perror("fail to pipe");
17         exit(1);
18     }
19 
20     pid = fork();
21     if(pid < 0)
22     {
23         perror("fail to fork");
24         exit(1);
25     }
26     else if(pid == 0)   //子   fd[1]
27     {
28         close(fd[0]);//不操作读端,关闭文件描述符fd[0]
29         char buf[20];
30         bzero(buf,sizeof(buf));
31         fgets(buf,sizeof(buf),stdin);
32         write(fd[1],buf,strlen(buf));
33 
34         exit(0);
35     }
36     else  //父  fd[0]
37     {
38         sleep(5);
39         close(fd[1]);//不操作写端,关闭fd[1];
40         char recv[20];
41         bzero(recv,sizeof(recv));
42         read(fd[0],recv,sizeof(recv));
43         printf("recv:%s\n",recv);
44         wait(NULL);
45     }
46 
47 
48     return 0;
49 }
pipe

2.有名管道: 利用文件系统实现两个进程找到内核中的管道(挂载了一个节点)
mkfifo:
int mkfifo(const char *pathname, mode_t mode);
功能:创建有名管道文件
参数:1.创建管道文件所在路径 2.权限 0666 实际真实权限:(mode & ~umask)
返回值:成功返回0,失败返回-1,并设置errno号
EEXIST:测试指定路径下的文件是否已存在,存在报该错误,容错时排除

注:
1.操作时读端必须先打开,防止出现错误管道破裂!!!
2.创建的有名管道文件类型是p,且无大小(在ROM上没有被存放),禁止使用lseek进行操作

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <errno.h>
 5 #include <stdlib.h>
 6 #include <fcntl.h>
 7 #include <strings.h>
 8 
 9 
10 int main(int argc, const char *argv[])
11 {
12     //创建管道文件:
13     if(-1 == mkfifo("/home/xyx/myfifo",0666))
14     {
15         if(errno != EEXIST)
16         {
17             perror("fail to mkfifo");
18             exit(1);
19         }
20     }
21 
22     int fd;
23     //以读方式打开管道文件
24     fd = open("/home/xyx/myfifo",O_RDONLY);
25     if(fd == -1)
26     {
27         perror("fail to open");
28         exit(1);
29     }
30 
31     char buf[128];
32 
33     while(1)
34     {
35         bzero(buf,sizeof(buf));
36         read(fd,buf,sizeof(buf));
37         printf("recv:%s\n",buf);
38         if(strncmp(buf,"quit",4) == 0)
39             exit(0);
40     }
41 
42 
43     return 0;
44 }
fifo_read
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <errno.h>
 5 #include <stdlib.h>
 6 #include <fcntl.h>
 7 #include <strings.h>
 8 #include <string.h>
 9 
10 
11 int main(int argc, const char *argv[])
12 {
13     //创建管道文件:由于读端先打开,所以读端先创建管道,该代码可以在写端不写
14     if(-1 == mkfifo("/home/xyx/myfifo",0666))
15     {
16         if(errno != EEXIST)
17         {
18             perror("fail to mkfifo");
19             exit(1);
20         }
21     }
22 
23     int fd;
24     //以写方式打开管道文件
25     fd = open("/home/xyx/myfifo",O_WRONLY);
26     if(fd == -1)
27     {
28         perror("fail to open");
29         exit(1);
30     }
31 
32     char buf[128];
33 
34     while(1)
35     {
36         bzero(buf,sizeof(buf));
37         fgets(buf,sizeof(buf),stdin);
38         
39         //删除fgets中的'\n'
40         if(buf[strlen(buf)-1] == '\n')    
41             buf[strlen(buf)-1] = '\0';
42 
43         write(fd,buf,strlen(buf));//真实数据的长度
44         if(strncmp(buf,"quit",4) == 0)
45             exit(0);
46     }
47 
48 
49     return 0;
50 }
fifo_write

3.信号:
1.由内核发送给进程
2.是一种异步机制,是一种软中断

kill命令:给进程发送指定信号
kill -l查看信号
可靠信号: 后面的新的信号
不可靠信号: 前面的旧的信号
注:大部分的信号都是杀死进程

当进程接受到信号时的处理手段:
1.默认处理 ctrl+c SIGINT 2 ctrl+z SIGSTOP 19
2.被忽略 SIG_IGN
3.被捕获 signal
注:9,19不能忽略和捕获

kill函数:给进程发送指定信号
int kill(pid_t pid, int sig);
参数:1.指定进程pid 2.信号编号
返回值:成功返回0,失败返回-1,并设置errno号
对比kill命令:kill -signum pid

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5 #include <signal.h>
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     pid_t pid;
12 
13 
14     pid = fork();
15     if(pid < 0)
16     {
17         perror("fail to fork");
18         exit(1);
19     }
20     else if(pid == 0)
21     {
22         while(1)
23         {
24             printf("i'm child!\n");
25             sleep(1);
26         }
27 
28         exit(0);
29     }
30     else
31     {
32         sleep(5);
33         kill(pid,SIGKILL);
34         wait(NULL);
35         exit(0);
36     }
37     return 0;
38 }
kill

raise:给当前调用进程发送信号
int raise(int sig);
参数:1.信号编号
返回值:成功返回0,失败返回非0值
kill(getpid(),sig) == raise(sig)

 1 #include <stdio.h>
 2 #include <signal.h>
 3 #include <sys/types.h>
 4 #include <unistd.h>
 5 
 6 
 7 
 8 
 9 
10 int main(int argc, const char *argv[])
11 {
12     sleep(2);
13 
14     kill(getpid(),SIGKILL);
15 //    raise(SIGKILL);
16     return 0;
17 }
raise

alarm:指定时间后发送SIGALRM的信号给当前进程 (自爆闹钟)
unsigned int alarm(unsigned int seconds);
参数:1.秒数 通常情况下不填0

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     alarm(10);
 9 
10 
11     while(1)
12     {
13         printf("11111111\n");
14         sleep(1);
15     }
16     return 0;
17 }
alarm

pause:阻塞进程直到进程收到任意信号
int pause(void);

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sys/types.h>
 4 
 5 
 6 
 7 
 8 int main(int argc, const char *argv[])
 9 {
10     printf("111111\n");
11     printf("getpid:%d\n",getpid());
12     pause();
13 
14     printf("222222\n");
15     return 0;
16 }
pause

signal
sighandler_t signal(int signum, sighandler_t handler);
参数:1.信号编号 2.函数指针 信号处理函数的入口地址 void 函数名(int(信号编号))
typedef void (*sighandler_t)(int);
void(*)(int) == sighandler_t 本质就是函数指针
功能:向内核注册对应信号,当当前进程收到该信号时,不会执行信号的默认操作,直接捕获信号
执行对应的信号处理函数(官方提供信号处理宏函数SIG_IGN(被忽略) SIG_DFL)
返回值:不关心
注:SIGKILL SIGSTOP无法被signal捕获和忽略

 1 #include <stdio.h>
 2 #include <signal.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 
 6 //信号处理函数
 7 void handler(int signum)
 8 {
 9     if(signum == SIGQUIT)
10     {
11         printf("ctrl + \\ is used!\n");
12     }
13     else if(signum == SIGINT)
14     {
15         printf("ctrl + c is used!\n");
16     }
17     else if(signum == SIGALRM)
18     {
19         printf("alarm is used!\n");
20     }
21     else  
22     {
23         printf("SIGKILL is used!\n");
24     }
25 }
26 
27 int main(int argc, const char *argv[])
28 {
29     printf("getpid:%d\n",getpid());    
30     signal(SIGINT,handler);
31     signal(SIGKILL,handler);//无法被捕获
32     signal(SIGALRM,handler);
33     signal(SIGQUIT,handler);//ctrl+\
34 
35     alarm(5);
36 
37      while(1)
38      {
39          sleep(1);
40          printf("i'm alive no one can kill me !\n");
41      }
42 
43 
44     return 0;
45 }
signal

二.IPC三件套: system V 的 IPC 贝尔实验室
ftok:令牌函数 让多个进程找到同一个事件(同一块地方)
key_t ftok(const char *pathname, int proj_id);
参数:1.已知或已存在的文件路径(借助该文件的inode) 2.随意的一个整形数值,保证需要沟通的进程数值一致
返回值:成功返回计算的key值,失败返回-1,并设置errno号

消息队列: 内核泛型链表 关键字链式队列
msgget:创建消息队列
int msgget(key_t key, int msgflg);
参数:1.key值 2.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
访问时:0666
返回值:成功时返回消息队列编号msgid 失败返回-1,并设置errno号
errno号为EEXIST时代表消息队列存在,容错时注意,直接访问消息队列即可

ipcs -q:查询消息队列

msgsnd 插入数据
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:1.msgid 2.插入数据的类型 必须以如下结构体形式书写
struct msgbuf {
long mtype; /* message type, must be > 0 */ 数据类型用于区分数据 >0
char mtext[1]; /* message data */ 正文内容
};
3.正文长度 sizeof(msgbuf) - sizeof(long) 4.填0默认阻塞等待数据写入 (IPC_NOWAIT非阻塞)
返回值:失败返回-1,并设置errno号,成功返回0

msgrcv 接收数据
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:1.msgid 2.接收数据的类型 (自己创建空间接收) 3.正文长度 4.>0 接收指定数据类型的消息=0 默认接受消息队列中第一个成员的数据
5.填0默认阻塞
返回值:失败返回-1,并设置errno号,成功返回0

msgctl
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:1.msgid 2.指令 删除时用IPC_RMID 3.删除时填NULL即可
返回值:失败返回-1,并设置errno号

注:消息队列一般写书写recv端 启动时先打开recv端 创建消息队列和删除消息队列都是recv操作

命令删除:ipcrm -q msgid

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/msg.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <strings.h>
 8 #include <string.h>
 9 //插入数据的类型
10 typedef struct node
11 {
12     long type;
13     char buf[128];
14 }msg_t;
15 
16 int main(int argc, const char *argv[])
17 {
18     //ftok   计算key值
19     key_t key;
20     key = ftok("/home/xyx/123.c",'a');
21     if(key == -1)
22     {
23         perror("fail to ftok");
24         exit(1);
25     }
26 
27     //msgget 创建链表
28     int msgid;
29     msgid = msgget(key,IPC_CREAT | IPC_EXCL | 0666);
30     if(msgid == -1)
31     {
32         if(errno == EEXIST)
33         {
34             //消息队列存在直接访问
35             msgid = msgget(key,0666);
36         }
37         else
38         {
39             perror("fail to msgget");
40             exit(1);
41         }
42     }
43 
44     //创建后检验消息队列
45     system("ipcs -q");
46 
47     //用于接收数据的空间
48     msg_t *recv;
49     recv = malloc(sizeof(msg_t));
50 
51 
52     while(1)
53     {
54 
55         bzero(recv,sizeof(msg_t));
56 
57         //接收数据 msgrcv
58         if(-1 == msgrcv(msgid,recv,sizeof(msg_t)-sizeof(long),100,0))
59         {
60             perror("fail to msgrcv");
61             exit(1);
62         }
63 
64         printf("recv:%s\n",recv->buf);
65 
66         if(strncmp(recv->buf,"quit",4) == 0)
67             break;
68 
69 
70     }
71     //删除消息队列 msgctl
72     msgctl(msgid,IPC_RMID,NULL);
73 
74     //检查是否成功删除
75     system("ipcs -q");
76 
77     free(recv);
78 
79     return 0;
80 }
msg_recv
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/msg.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <strings.h>
 8 #include <string.h>
 9 //插入数据的类型
10 typedef struct node
11 {
12     long type;
13     char buf[128];
14 }msg_t;
15 
16 int main(int argc, const char *argv[])
17 {
18     //ftok   计算key值
19     key_t key;
20     key = ftok("/home/xyx/123.c",'a');
21     if(key == -1)
22     {
23         perror("fail to ftok");
24         exit(1);
25     }
26 
27     //msgget 创建链表
28     int msgid;
29     msgid = msgget(key,IPC_CREAT | IPC_EXCL | 0666);
30     if(msgid == -1)
31     {
32         if(errno == EEXIST)
33         {
34             //消息队列存在直接访问
35             msgid = msgget(key,0666);
36         }
37         else
38         {
39             perror("fail to msgget");
40             exit(1);
41         }
42     }
43 
44     //创建后检验消息队列
45     system("ipcs -q");
46 
47     //开辟空间用于发送数据
48     msg_t *send;
49     send = malloc(sizeof(msg_t));
50 
51 
52     while(1)
53     {
54         //清空
55         bzero(send,sizeof(msg_t));
56 
57         //写入数据
58         send->type = 100; //标记消息类型为100 必须>0
59         fgets(send->buf,sizeof(send->buf),stdin);//填入数据
60 
61         //插入数据 msgsnd        
62         if(-1 == msgsnd(msgid,send,sizeof(msg_t)-sizeof(long),0))
63         {
64             perror("fail to msgsnd");
65             exit(1);
66         }
67 
68         if(strncmp(send->buf,"quit",4) == 0)
69             break;
70 
71     }    
72 
73     free(send);
74     return 0;
75 }
msg_send

共享内存:真实物理内存 关键字映射
ftok
ipcs -m 查询共享内存
ipcrm -m 共享内存号 命令删除共享内存

shmget:申请空间
int shmget(key_t key, size_t size, int shmflg);
参数:1.key 2.申请空间的大小 3.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
访问时:0666
返回值:成功返回shmid 失败返回-1,并设置errno号
errno号为EEXIST时代表共享内存存在,容错时注意,直接访问共享内存即可

shmat:映射
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:1.shmid 2.映射的虚拟地址 填NULL自动分配 3.权限 填0表示读写均可以 填SHM_RDONLY代表只读
返回值:成功返回映射的虚拟空间的首地址 失败返回(void *)-1 并设置errno号

shmdt:取消映射
int shmdt(const void *shmaddr);
参数:1.映射成功后返回的首地址

shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:1.shmid 2.指令 IPC_RMID删除指令 3.删除时填NULL即可

实现共享内存同步方式:
注:recv先开后关 初始化以及shmget以及shmctl均由recv操作 send循环使用时注意清空共享内存
1.flag flag在结构体中,放在共享内存中实现

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 //自己约定的传输数据格式
 9 typedef struct a
10 {
11     int led1;
12     int led2;
13     char buf[128];
14 }node_t;
15 
16 int main(int argc, const char *argv[])
17 {
18     //ftok 计算key值
19     key_t key;
20     
21     key = ftok("/home/xyx/123.c",'b');
22     if(key == -1)
23     {
24         perror("fail to ftok");
25         exit(1);
26     }
27 
28     //创建共享内存 shmget
29     int shmid;
30     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
31     if(shmid == -1)
32     {
33         if(errno == EEXIST)
34         {
35             shmid = shmget(key,sizeof(node_t),0666);
36         }
37         else
38         {
39             perror("fail to shmget");
40             exit(0);
41         }
42     }
43     
44     //检查共享内存是否创建成功
45     system("ipcs -m");
46 
47     //映射 shmat
48     node_t *addr;
49     addr = shmat(shmid,NULL,0);
50     if(addr == (void *)-1)
51     {
52         perror("fail to shmat");
53         exit(1);
54     }
55     
56     //do somthing
57     //初始化  led1 send  led2 recv
58     addr->led1 = 1;
59     addr->led2 = 0;
60         
61     while(1)
62     {
63         if(addr->led2 == 1)
64         {
65             printf("recv:%s\n",addr->buf);
66             addr->led2--;
67             addr->led1++;
68             if(strncmp(addr->buf,"quit",4) == 0)
69                 break;
70         }
71     }
72 
73     //取消映射 shmdt
74     shmdt(addr);
75 
76     
77     //销毁空间 shmctl
78     shmctl(shmid,IPC_RMID,NULL);
79 
80     system("ipcs -m");
81 
82     return 0;
83 }
flag_recv
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 //自己约定的传输数据格式
 9 typedef struct a
10 {
11     int led1;
12     int led2;
13     char buf[128];
14 }node_t;
15 
16 int main(int argc, const char *argv[])
17 {
18     //ftok 计算key值
19     key_t key;
20     
21     key = ftok("/home/xyx/123.c",'b');
22     if(key == -1)
23     {
24         perror("fail to ftok");
25         exit(1);
26     }
27 
28     //创建共享内存 shmget
29     int shmid;
30     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
31     if(shmid == -1)
32     {
33         if(errno == EEXIST)
34         {
35             shmid = shmget(key,sizeof(node_t),0666);
36         }
37         else
38         {
39             perror("fail to shmget");
40             exit(0);
41         }
42     }
43     
44     //检查共享内存是否创建成功
45     system("ipcs -m");
46 
47     //映射 shmat
48     node_t *addr;
49     addr = shmat(shmid,NULL,0);
50     if(addr == (void *)-1)
51     {
52         perror("fail to shmat");
53         exit(1);
54     }
55     
56     //do somthing
57     while(1)
58     {
59         if(addr->led1 == 1)
60         {
61             memset(addr->buf,0,128);
62             fgets(addr->buf,sizeof(addr->buf),stdin);
63 
64             addr->led1--;
65             addr->led2++;
66 
67             if(strncmp(addr->buf,"quit",4) == 0)
68                 break;
69         }
70     }
71     
72 
73     //取消映射 shmdt
74     shmdt(addr);
75 
76 
77     return 0;
78 }
flag_send

2.信号

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <unistd.h>
 8 #include <signal.h>
 9 #include <string.h>
10 //自己约定的传输数据格式
11 typedef struct a
12 {
13     pid_t pid_send;
14     pid_t pid_recv;
15     char buf[128];
16 }node_t;
17 
18 //信号处理函数
19 void handler(int signum)   
20 {
21     ;
22 }
23 
24 int main(int argc, const char *argv[])
25 {
26     //ftok 计算key值
27     key_t key;
28 
29     key = ftok("/home/xyx/123.c",'b');
30     if(key == -1)
31     {
32         perror("fail to ftok");
33         exit(1);
34     }
35 
36     //创建共享内存 shmget
37     int shmid;
38     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
39     if(shmid == -1)
40     {
41         if(errno == EEXIST)
42         {
43             shmid = shmget(key,sizeof(node_t),0666);
44         }
45         else
46         {
47             perror("fail to shmget");
48             exit(0);
49         }
50     }
51 
52     //检查共享内存是否创建成功
53     system("ipcs -m");
54 
55     //映射 shmat
56     node_t *addr;
57     addr = shmat(shmid,NULL,0);
58     if(addr == (void *)-1)
59     {
60         perror("fail to shmat");
61         exit(1);
62     }
63 
64     //do somthing
65     addr->pid_recv = getpid();
66 
67     //SIGUSR1 recv->send      SIGUSR2 send->recv
68     signal(SIGUSR2,handler);  //捕获信号,不做任何操作
69 
70 
71     while(1)
72     {
73         pause(); //阻塞等待
74         printf("recv:%s\n",addr->buf);
75 
76         if(strncmp(addr->buf,"quit",4) == 0)
77             break;
78 
79         kill(addr->pid_send,SIGUSR1);
80     }
81 
82     //取消映射 shmdt
83     shmdt(addr);
84 
85 
86     //销毁空间 shmctl
87     shmctl(shmid,IPC_RMID,NULL);
88 
89     system("ipcs -m");
90 
91     return 0;
92 }
signal_recv
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <unistd.h>
 8 #include <string.h>
 9 #include <signal.h>
10 //自己约定的传输数据格式
11 typedef struct a
12 {
13     pid_t pid_send;
14     pid_t pid_recv;
15     char buf[128];
16 }node_t;
17 
18 void handler(int signum)
19 {
20     ;
21 }
22 
23 
24 int main(int argc, const char *argv[])
25 {
26     //ftok 计算key值
27     key_t key;
28     
29     key = ftok("/home/xyx/123.c",'b');
30     if(key == -1)
31     {
32         perror("fail to ftok");
33         exit(1);
34     }
35 
36     //创建共享内存 shmget
37     int shmid;
38     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
39     if(shmid == -1)
40     {
41         if(errno == EEXIST)
42         {
43             shmid = shmget(key,sizeof(node_t),0666);
44         }
45         else
46         {
47             perror("fail to shmget");
48             exit(0);
49         }
50     }
51     
52     //检查共享内存是否创建成功
53     system("ipcs -m");
54 
55     //映射 shmat
56     node_t *addr;
57     addr = shmat(shmid,NULL,0);
58     if(addr == (void *)-1)
59     {
60         perror("fail to shmat");
61         exit(1);
62     }
63     
64     //do somthing
65     addr->pid_send = getpid();
66 
67     signal(SIGUSR1,handler);
68     
69     while(1)
70     {
71         memset(addr->buf,0,sizeof(addr->buf));
72 
73         fgets(addr->buf,sizeof(addr->buf),stdin);
74 
75         kill(addr->pid_recv,SIGUSR2);
76 
77         if(strncmp(addr->buf,"quit",4) == 0)
78             break;
79 
80         pause();
81     }
82 
83     //取消映射 shmdt
84     shmdt(addr);
85 
86     return 0;
87 }
signal_send

3.信号灯集

信号灯集: 瞬间操作多盏信号灯,信号量的集合
ftok
ipcs -s
ipcrm -s semid

semget :创建信号灯集
int semget(key_t key, int nsems, int semflg);
参数:1.key 2.信号灯的数量 3.权限 创建时:IPC_CREAT | IPC_EXCL | 0666
访问时:0666
返回值:成功执行返回semid,失败返回-1,并设置errno号
errno号为EEXIST时代表信号灯集存在,容错时注意,直接访问信号灯集即可

semctl: 初始化操作 相当于线程中sem_init
int semctl(int semid, int semnum, int cmd, ...);
参数:1.semid 2.指定的灯号 3.指令 SETVAL对指定灯初始化
4.可选参数,根据参数3决定是否使用,使用时必须定义如下联合体
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};

semop: pv操作 相当于线程中sem_post sem_wait
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:1.semid 2.p,v操作的结构体,类型如下
unsigned short sem_num; /* semaphore number */ 信号量的编号
short sem_op; /* semaphore operation */ p,v操作 +1 -1
short sem_flg; /* operation flags */ 使用SEM_UNDO
3.一次性操作的灯数
返回值:成功返回0,失败返回-1,并设置errno号

semctl:销毁信号灯集
int semctl(int semid, int semnum, int cmd, ...);
参数:1.semid 2.使用IPC_RMID时忽略改参数 填0 3.删除使用IPC_RMID 4.不使用

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <stdlib.h>
 5 #include <sys/sem.h>
 6 #include <errno.h>
 7 
 8 typedef struct a
 9 {
10     char buf[128];
11 }node_t;
12 
13 
14 //封装semctl 实现sem_init
15 int mysem_init(int semid,int n,int value)
16 { 
17     union semun {
18         int        val;    /* Value for SETVAL */
19         struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
20         unsigned short  *array;    /* Array for GETALL, SETALL */
21         struct seminfo  *__buf;    /* Buffer for IPC_INFO
22                                    (Linux-specific) */
23     };
24 
25     union semun buf;
26     buf.val = value;
27     if(-1 == semctl(semid,n,SETVAL,buf))
28     {
29         perror("fail to semctl");
30         exit(1);
31     }
32 
33     return 0;
34 }
35 
36 //封装semop 实现sem_post sem_wait
37 int mysem_post(int semid,int n)
38 {
39     struct sembuf buf;
40     buf.sem_num = n;
41     buf.sem_op = 1;
42     buf.sem_flg = SEM_UNDO;
43 
44     if(-1 == semop(semid,&buf,1))
45     {
46         perror("fail to semop");
47         exit(1);
48     }
49 
50     return 0;
51 }
52 
53 
54 int mysem_wait(int semid,int n)    
55 {
56     struct sembuf buf;
57     buf.sem_num = n;
58     buf.sem_op = -1;
59     buf.sem_flg = SEM_UNDO;
60 
61     if(-1 == semop(semid,&buf,1))
62     {
63         perror("fail to semop");
64         exit(1);
65     }
66 
67     return 0;
68 }
sem_h
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <sys/sem.h>
 9 
10 #include "shm_sem.h"
11 
12 int main(int argc, const char *argv[])
13 {
14     //ftok 计算key值
15     key_t key;
16     
17     key = ftok("/home/xyx/123.c",'b');
18     if(key == -1)
19     {
20         perror("fail to ftok");
21         exit(1);
22     }
23 
24     //创建共享内存 shmget
25     int shmid;
26     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
27     if(shmid == -1)
28     {
29         if(errno == EEXIST)
30         {
31             shmid = shmget(key,sizeof(node_t),0666);
32         }
33         else
34         {
35             perror("fail to shmget");
36             exit(0);
37         }
38     }
39     
40     //创建信号灯集
41     int semid;
42     semid = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
43     if(semid == -1)
44     {
45         if(errno == EEXIST)
46         {
47             semid = semget(key,2,0666);
48         }
49         else
50         {
51             perror("fail to semget");
52             exit(1);
53         }
54     }
55 
56     //检查共享内存和信号灯集是否创建成功
57     system("ipcs -m");
58     system("ipcs -s");
59     
60     //映射 shmat
61     node_t *addr;
62     addr = shmat(shmid,NULL,0);
63     if(addr == (void *)-1)
64     {
65         perror("fail to shmat");
66         exit(1);
67     }
68     
69     //do somthing
70     //初始化
71     mysem_init(semid,0,1);  //0灯给send
72     mysem_init(semid,1,0);  //1灯给recv
73     
74     while(1)
75     {
76         mysem_wait(semid,1);//1灯-1
77         printf("recv:%s\n",addr->buf);
78 
79         if(strncmp(addr->buf,"quit",4) == 0)
80             break;
81 
82         mysem_post(semid,0);//0灯+1
83     }
84 
85     //取消映射 shmdt
86     shmdt(addr);
87 
88     
89     //销毁空间 shmctl
90     shmctl(shmid,IPC_RMID,NULL);
91 
92     //销毁信号灯集 
93     semctl(semid,0,IPC_RMID);
94 
95 
96     system("ipcs -m");
97     system("ipcs -s");
98     return 0;
99 }
sem_recv
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/ipc.h>
 4 #include <sys/shm.h>
 5 #include <stdlib.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <sys/sem.h>
 9 
10 #include "shm_sem.h"
11 
12 int main(int argc, const char *argv[])
13 {
14     //ftok 计算key值
15     key_t key;
16     
17     key = ftok("/home/xyx/123.c",'b');
18     if(key == -1)
19     {
20         perror("fail to ftok");
21         exit(1);
22     }
23 
24     //创建共享内存 shmget
25     int shmid;
26     shmid = shmget(key,sizeof(node_t),IPC_CREAT | IPC_EXCL | 0666);
27     if(shmid == -1)
28     {
29         if(errno == EEXIST)
30         {
31             shmid = shmget(key,sizeof(node_t),0666);
32         }
33         else
34         {
35             perror("fail to shmget");
36             exit(0);
37         }
38     }
39     
40     //创建信号灯集
41     int semid;
42     semid = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);
43     if(semid == -1)
44     {
45         if(errno == EEXIST)
46         {
47             semid = semget(key,2,0666);
48         }
49         else
50         {
51             perror("fail to semget");
52             exit(1);
53         }
54     }
55 
56     //检查共享内存和信号灯集是否创建成功
57     system("ipcs -m");
58     system("ipcs -s");
59     
60     //映射 shmat
61     node_t *addr;
62     addr = shmat(shmid,NULL,0);
63     if(addr == (void *)-1)
64     {
65         perror("fail to shmat");
66         exit(1);
67     }
68     
69     //do somthing
70     //初始化
71     mysem_init(semid,0,1);  //0灯给send
72     mysem_init(semid,1,0);  //1灯给recv
73     
74     while(1)
75     {
76         mysem_wait(semid,1);//1灯-1
77         printf("recv:%s\n",addr->buf);
78 
79         if(strncmp(addr->buf,"quit",4) == 0)
80             break;
81 
82         mysem_post(semid,0);//0灯+1
83     }
84 
85     //取消映射 shmdt
86     shmdt(addr);
87 
88     
89     //销毁空间 shmctl
90     shmctl(shmid,IPC_RMID,NULL);
91 
92     //销毁信号灯集 
93     semctl(semid,0,IPC_RMID);
94 
95 
96     system("ipcs -m");
97     system("ipcs -s");
98     return 0;
99 }
sem_send

socket一打六,

原文地址:https://www.cnblogs.com/hslixiqian/p/9559480.html