学习笔记(四)之进程之间的通信
进程间通信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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
二.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 }
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 }
共享内存:真实物理内存 关键字映射
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 }
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 }
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 }
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 }
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 }
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 }
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 }
socket一打六,