信号量、消息队列、共享内存复习

2/10/2017来源:ASP.NET技巧人气:268

信号量代码

使用信号量实现父子进程间同步:

#include <sys/sem.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> 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) */ }; void pv(int sem_id, int op) { struct sembuf sem_b; sem_b.sem_num = 0; sem_b.sem_op = op; sem_b.sem_flg = SEM_UNDO; semop(sem_id, &sem_b, 1); } int main(int argc, char** argv) { int sem_id = semget(IPC_PRIVATE, 1, 0666); union semun sem_un; sem_un.val = 1; semctl(sem_id, 0, SETVAL, sem_un); pid_t pid = fork(); if(pid < 0) return -1; else if(pid == 0){ printf("child try to get binary sem\n"); pv(sem_id, -1); printf("child get the sem and would release it after 5 seconds\n"); sleep(5); pv(sem_id, 1); exit(0); } else{ printf("parent try to get binary sem\n"); pv(sem_id, -1); printf("parent get the sem and would release it agter 5 SEOcnds\n"); sleep(5); pv(sem_id, 1); } waitpid(pid, NULL, 0); semctl(sem_id, 0, IPC_RMID, sem_un); return 0; }

消息队列代码

使用消息队列实现简单的进程间交谈。

utili.h头文件:

#pragma once #include <stdio.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <string.h> const char* const PATH_NAME = "pathname"; const int PRO_ID = 0xff; const int BUFFER_SIZE = 256; struct message { long msg_type; char msg_text[BUFFER_SIZE]; };

server.cpp:

#include "utili.h" const int SERVER_MSG_SND_TYPE = 10000; const int SERVER_MSG_RCV_TYPE = 2; int main() { int msg_id; if(msg_id = msgget(ftok(PATH_NAME, PRO_ID), IPC_CREAT | IPC_EXCL | 0755) < 0){ perror("what"); exit(-1); } printf("msg_id = %d\n", msg_id); message msg; for(; ;){ printf("server:>"); scanf("%s", msg.msg_text); if(strncasecmp(msg.msg_text, "quit", 4) == 0) break; msg.msg_type = SERVER_MSG_SND_TYPE; msgsnd(msg_id, &msg, strlen(msg.msg_text)+1, 0); msgrcv(msg_id, &msg, BUFFER_SIZE, SERVER_MSG_RCV_TYPE, 0); printf("client:>%s\n", msg.msg_text); } msgctl(msg_id, IPC_RMID, 0); while(1); exit(0);

客户端:

#include "utili.h" const int CLIENT_MSG_SND_TYPE = 2; const int CLIENT_MSG_RCV_TYPE = 10000; int main() { int msg_id; key_t msg_key = ftok(PATH_NAME, PRO_ID); if(msg_key < 0){ perror("what1"); exit(-1); } printf("msg_key = %d\n", msg_key); if((msg_id = msgget(msg_key, 0)) < 0){ perror("what2"); exit(-1); } printf("mid_id = %d\n", msg_id); message msg; for(; ;){ msgrcv(msg_id, &msg, BUFFER_SIZE, CLIENT_MSG_RCV_TYPE, 0); printf("serverhehf:>%s\n", msg.msg_text); printf("clientwowo:>"); scanf("%s", msg.msg_text); if(strncasecmp(msg.msg_text, "quit", 4) == 0) break; msg.msg_type = CLIENT_MSG_SND_TYPE; msgsnd(msg_id, &msg, strlen(msg.msg_text)+1, 0); } msgctl(msg_id, IPC_RMID, 0); exit(0); }

双反接收和发送的消息类型不同,可以利用这点从消息队列中取自己的消息。

昨天晚上写消息队列这个程序坑了我好长时间,没有使用perror判断错误外加没有注意到ftok函数针对的path必须是真实存在的文件或目录,然后找BUG找了一个半多小时。

共享内存代码

这里使用共享内存来实现服务器和客户端通信,并且由于共享了读写,使用信号量来同步。

utili.h:

#include <stdio.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/ipc.h> #include <stdlib.h> #include <string.h> #define PATHNAME "newfile" #define PRO_ID 0xff #define err_exit(m) \ do{ \ perror(m); \ exit(1); \ }while(0) #define USE_SEM 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*/ };

server.cpp:

#include "utili.h" int main(int argc, char** argv) { int shm_id; if( (shm_id = shmget(ftok(PATHNAME, PRO_ID), 1024, IPC_CREAT|IPC_EXCL|0755)) < 0) err_exit("shmget err."); char *ch; if( (ch = (char *)shmat(shm_id, NULL, 0)) == (void *)-1) err_exit("shmat err"); #ifdef USE_SEM int sem_id; if( (sem_id = semget(ftok(PATHNAME, PRO_ID), 2, IPC_CREAT|IPC_EXCL|0755)) < 0){ shmdt(ch); shmctl(shm_id, IPC_RMID, 0); err_exit("semget err."); } union semun init; init.val = 0; semctl(sem_id, 0, SETVAL, init); //0 semctl(sem_id, 1, SETVAL, init); //1 struct sembuf p = {0, -1, 0}, v = {1, 1, 0}; #endif for(; ;){ printf("server:>"); scanf("%s", ch); if(strncasecmp(ch, "quit", 4) == 0){ shmdt(ch); break; } semop(sem_id, &v, 1); semop(sem_id, &p, 1); printf("client:>%s\n", ch); } int res; if( (res = shmctl(shm_id, IPC_RMID, 0)) < 0) err_exit("remove err."); return 0; }

client.cpp:

#include "utili.h" int main(int argc, char** argv) { int shm_id; if( (shm_id = shmget(ftok(PATHNAME, PRO_ID), 0, 0)) < 0) err_exit("shmget err."); char *ch; if( (ch = (char *)shmat(shm_id, NULL, 0)) == (void *)-1) err_exit("shmat err"); #ifdef USE_SEM int sem_id; if( (sem_id = semget(ftok(PATHNAME, PRO_ID), 0, 0)) < 0){ shmdt(ch); shmctl(shm_id, IPC_RMID, 0); err_exit("semget err."); } union semun init; init.val = 0; semctl(sem_id, 0, SETVAL, init); //0 semctl(sem_id, 1, SETVAL, init); //1 struct sembuf p = {1, -1, 0}, v = {0, 1, 0}; #endif for(; ;){ semop(sem_id, &p, 1); printf("server:>%s\n", ch); printf("cli:>"); scanf("%s", ch); if(strncasecmp(ch, "quit", 4) == 0){ shmdt(ch); break; } semop(sem_id, &v, 1); } int res; if( (res = shmctl(shm_id, IPC_RMID, 0)) < 0) err_exit("remove err."); return 0; }