• C语言:详细介绍了六种进程间通讯方式(还有一种socket在主页关于socket的介绍里面有详细介绍,欢迎观看)


    一.无名管道

    1.1无名管道的原理

    无名管道只能用于亲缘间进程的通信,无名管道的大小是64K。无名管道是内核空间实现的机制。

    1.2功能

     1) Pipe()创建一个管道,这是一个单向的数据通道,可用于进程间通信。

    2)数组pipefd用于返回两个指向管道末端的文件描述符。

    3)Pipefd[0]指的是管道的读端。Pipefd[1]指的是管道的写入端,写入管道的写入端数据由内核进行缓冲(64k),直到从管道的读取端读取为止。

    1.3无名管道通信特点

    1.只能用于亲缘间进程的通信

    2.无名管道数据半双工的通信的方式

    ​ 单工 : A -------------->B

    ​ 半双工 : 同一时刻 A----->B B------>A

    ​ 全双工 : 同一时刻 A<---->B

    3.无名管道的大小是64K

    4.无名管道不能够使用lseek函数

    5.读写的特点

    如果读端存在写管道:有多少写多少,直到写满为止(64k)写阻塞

    如果读端不存写管道,管道破裂(SIGPIPE) (可以通过gdb调试看现象)

    如果写端存在读管道:有多少读多少,没有数据的时候阻塞等待

    如果写端不存在读管道:有多少读多少,没有数据的时候立即返回

    1.4无名管道的实例

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define ERROR(msg) do{\
    9. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    10. printf(msg);\
    11. exit(-1); \
    12. }while(0)
    13. int main(int argc, char const *argv[])
    14. {
    15. pid_t pid;
    16. int num[2];
    17. char buff[128] = {0};
    18. if (pipe(num)){
    19. ERROR("pipe error");
    20. }
    21. if ((pid = fork()) == -1){
    22. ERROR("fork error");
    23. }else if(pid == 0){
    24. close(num[0]);
    25. while (1){
    26. memset(buff, 0, sizeof(buff));
    27. printf("请输入您要输入的数值>>");
    28. fgets(buff, sizeof(buff), stdin);
    29. buff[strlen(buff) -1] = '\0';
    30. write(num[1], buff, strlen(buff));
    31. if (!strncmp(buff, "quit", 4)){
    32. break;
    33. }
    34. }
    35. close(num[1]);
    36. exit(EXIT_SUCCESS);
    37. }else{
    38. close(num[1]);
    39. while (1){
    40. memset(buff, 0, sizeof(buff));
    41. read(num[0], buff, sizeof(buff));
    42. if (!strncmp(buff, "quit", 4)){
    43. break;
    44. }
    45. printf("%s\n",buff);
    46. }
    47. close(num[0]);
    48. wait(NULL);
    49. }
    50. return 0;
    51. }

    二.有名管道

    2.1有名管道的原理

    1)可以用于亲缘间进程的通信,也可以用于非亲缘间的进程的通信。

    2)有名管道会创建一个文件,需要通信的进程打开这个文件,产生文件描述符后就可以通信了,有名管道的文件存在内存上。

    3)有名管道的大小也是64K,也不能使用lseek函数

    2.2有名管道的特点

    1.可以用于任意进程间的通信

    2.有名管道数据半双工的通信的方式

    3.有名管道的大小是64K

    4.有名管道不能够使用lseek函数

    5.读写的特点

    如果读端存在写管道:有多少写多少,直到写满为止(64k)写阻塞

    如果读端不存写管道

    ​ 1.读权限没有打开,写端在open的位置阻塞

    ​ 2.读端打开后关闭,管道破裂(SIGPIPE) (可以通过gdb调试看现象)

    如果写端存在读管道:有多少读多少,没有数据的时候阻塞等待

    如果写端不存在读管道

    ​ 1.写权限没有打开,读端在open的位置阻塞

    ​ 2.写端打开后关闭,有多少读多少,没有数据的时候立即返回

    2.3有名管道实例:

    mkfifo文件:

    1. #include
    2. #include
    3. #define ERROR(msg) do{\
    4. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    5. printf(msg);\
    6. exit(-1); \
    7. }while(0)
    8. int main(int argc, char const *argv[])
    9. {
    10. if (mkfifo("./fifo",0666)){
    11. ERROR("mkfifo error");
    12. }
    13. //有名管道没有阻塞,手动加一个阻塞
    14. getchar();
    15. system("rm ./fifo -rf");
    16. return 0;
    17. }

    write文件:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define ERROR(msg) do{\
    9. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    10. printf(msg);\
    11. exit(-1); \
    12. }while(0)
    13. int main(int argc, char const *argv[])
    14. {
    15. int fd;
    16. char buff[128] = {0};
    17. if ((fd = open("./fifo",O_WRONLY)) == -1){
    18. ERROR("open fifo error\n");
    19. }
    20. while(1){
    21. printf("input >");
    22. fgets(buff, sizeof(buff), stdin);
    23. buff[strlen(buff) - 1] = '\0';
    24. write(fd, buff, strlen(buff));
    25. if(!strncmp("quit",buff,4))break;
    26. }
    27. close(fd);
    28. return 0;
    29. }

    read文件:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define ERROR(msg) \
    10. do \
    11. { \
    12. printf("%s %s %d\n", __FILE__, __func__, __LINE__); \
    13. printf(msg); \
    14. exit(-1); \
    15. } while (0)
    16. int main(int argc, char const *argv[])
    17. {
    18. int fd;
    19. char buff[128] = {0};
    20. if ((fd = open("./fifo", O_RDONLY)) == -1)
    21. {
    22. ERROR("open error");
    23. }
    24. while (1){
    25. memset(buff, 0, sizeof(buff));
    26. read(fd, buff, sizeof(buff));
    27. if (!strncmp("quit",buff,4)){
    28. break;
    29. }
    30. printf("%s\n",buff);
    31. }
    32. close(fd);
    33. return 0;
    34. }

    三.信号

    3.1信号的概念

    信号是中断的一种软件模拟,中断是基于硬件实现的,信号是基于linux内核实现的。

    用户可以给进程发信号,进程可以给进程发信号,内核也可以给进程发信号。进程对

    信号的处理方式有三种:捕捉,忽略,默认

    3.2发送信号的函数

    1. int raise(int sig);
    2. 功能:给自己(进程或者线程)发信号
    3. 参数:
    4. @sig:信号号
    5. 返回值:成功返回0,失败返回非0
    6. int kill(pid_t pid, int sig);
    7. 功能:给进程发信号
    8. 参数:
    9. @pid:进程号
    10. pid > 0 :给pid对应的进程发信号
    11. pid = 0 :给同组的进程发信号
    12. pid = -1:给所有的有权限操作的进程发送信号,init进程除外
    13. pid < -1:给-pid对应的同组的进程发信号
    14. @sig:信号号
    15. 返回值:成功返回0,失败返回-1置位错误码

    3.2常用的信号

     

    1.在上述的信号中只有SIGKILL和SIGSTOP两个信号不能被捕捉也不能被忽略

    2.SIGCHLD,当子进程结束的时候,父进程收到这个SIGCHLD的信号

    3.3实例:

    3.3.1捕捉ctrl+c

    1. #include
    2. #include
    3. #include
    4. #define ERROR(msg) do{\
    5. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    6. printf(msg);\
    7. exit(-1); \
    8. }while(0)
    9. void handle(int num)
    10. {
    11. if (num == SIGINT){
    12. printf("我收到一个ctrl+c的信号\n");
    13. }
    14. }
    15. int main(int argc, char const *argv[])
    16. {
    17. //捕捉
    18. if (signal(SIGINT, handle) == SIG_ERR){
    19. ERROR("register signal error");
    20. }
    21. //忽略
    22. if (signal(SIGINT,SIG_IGN) == SIG_ERR){
    23. ERROR("register signal error");
    24. }
    25. //默认
    26. if (signal(SIGINT,SIG_DFL) == SIG_ERR){
    27. ERROR("register signale");
    28. }
    29. while(1);
    30. return 0;
    31. }

    3.3.2捕捉管道破裂的消息:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define ERROR(msg) do{\
    7. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    8. printf(msg);\
    9. exit(-1); \
    10. }while(0)
    11. void handle(int num)
    12. {
    13. if (num == SIGPIPE){
    14. printf("捕捉到一条管道破裂的消息\n");
    15. }
    16. }
    17. int main(int argc, char const *argv[])
    18. {
    19. int num[2];
    20. char buff[32] = "123";
    21. if(pipe(num)){
    22. ERROR("pipe error");
    23. }
    24. if (signal(SIGPIPE,handle) == SIG_ERR){
    25. ERROR("signal error");
    26. }
    27. close(num[0]);
    28. write(num[1],buff,strlen(buff));
    29. return 0;
    30. }

    3.3.3阻塞等待为子进程回收资源:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. void signal_handle(int signo)
    7. {
    8. printf("我是父进程,收到了子进程退出的信号,为它回收资源\n");
    9. waitpid(-1,NULL,WNOHANG); //非阻塞方式回收资源
    10. printf("为子进程回收资源成功\n");
    11. raise(SIGKILL); //给父进程发送信号,结束父进程
    12. }
    13. int main(int argc,const char * argv[])
    14. {
    15. pid_t pid;
    16. pid = fork();
    17. if(pid == -1){
    18. ERROR("fork error");
    19. }else if(pid == 0){
    20. sleep(5);
    21. printf("子进程执行结束了\n");
    22. exit(EXIT_SUCCESS);
    23. }else{
    24. if(signal(SIGCHLD,signal_handle)==SIG_ERR)
    25. ERROR("signal error");
    26. while(1);
    27. }
    28. return 0;
    29. }

    3.3.4用arlarm实现一个斗地主机制

    1. #include
    2. #include
    3. #include
    4. #include
    5. #define ERROR(msg) do{\
    6. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    7. printf(msg);\
    8. exit(-1); \
    9. }while(0)
    10. void handle(int num)
    11. {
    12. if (num == SIGALRM){
    13. printf("自动出牌\n");
    14. }
    15. alarm(3);
    16. }
    17. int main(int argc, char const *argv[])
    18. {
    19. char ch;
    20. if (signal(SIGALRM,handle) == SIG_ERR){
    21. ERROR("signale error");
    22. }
    23. alarm(3);
    24. while (1){
    25. printf("请输入您要出的牌>>");
    26. ch = getchar();
    27. getchar();
    28. printf("%c\n",ch);
    29. alarm(3);
    30. }
    31. return 0;
    32. }

    四.IPC进程间通信

    4.1IPC进程间通信的种类

    (1)消息队列

    (2)共享内存

    (3)信号灯集

    4.2查看IPC进程间通信的命令

    4.2.1查看

    ipcs -q //查看消息队列的命令

    ipcs -m //查看共享内存的命令

    ipcs -s //查看信号灯集的命令

    4.2.2删除ipc的命令

    ipcrm -q msqid //删除消息队列命令

    ipcrm -m shmid //删除共享内存命令

    ipcrm -s semid //删除信号灯集的命令

    4.3消息队列

    4.3.1消息队列的原理

    消息队列也是借助内核实现的,A进程将消息放到消息队列中,队列中的消息

    有消息的类型和消息的正文。B进程可以根据想取的消息的类型从消息队列中

    将消息读走。消息队列默认的大小是16384个字节。如果消息队列中的消息满了,

    A进程还想往队列中发消息,此时A进程阻塞。

    4.3.2IPC进程间通信键值的获取

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define ERROR(msg) do{\
    8. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    9. printf(msg);\
    10. exit(-1); \
    11. }while(0)
    12. int main(int argc, char const *argv[])
    13. {
    14. key_t key;
    15. struct stat st;
    16. if ((key = ftok("/home/linux",'w')) == -1){
    17. ERROR("ftok error");
    18. }
    19. printf("key=%#x\n",key);
    20. if (stat("/home/linux",&st)){
    21. ERROR("stat error");
    22. }
    23. printf("pro_id=%#x,devno=%#lx,ino=#=%#lx\n",'w',st.st_dev,st.st_ino);
    24. return 0;
    25. }

    结果图:

    4.3.3消息队列的实例:(不关注类型的)

    头文件:

    1. #ifndef __MYHEAD_H__
    2. #define __MYHEAD_H__
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #define PRINT_ERR(msg) do{\
    12. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    13. printf(msg);\
    14. exit(-1); \
    15. }while(0)
    16. #define MSGSIZE (sizeof(msg_t)-sizeof(long))
    17. typedef struct mubuf{
    18. long mtype;
    19. char text[512];
    20. }msg_t;
    21. #endif

    发送方:

    1. #include "myhead.h"
    2. int main(int argc, char const *argv[])
    3. {
    4. key_t key;
    5. int msqid;
    6. msg_t msg ={
    7. .mtype = 100,
    8. };
    9. if((key = ftok("/home/linux/",'r'))==-1)
    10. PRINT_ERR("ftok get key error");
    11. if((msqid = msgget(key,IPC_CREAT|0666))==-1)
    12. PRINT_ERR("create msg queue error");
    13. while (1){
    14. memset(msg.text,0,sizeof(msg.text));
    15. fgets(msg.text,MSGSIZE,stdin);
    16. msg.text[strlen(msg.text) - 1] = '\0';
    17. msgsnd(msqid, &msg, MSGSIZE, 0);
    18. if (!strncmp(msg.text,"quit",4)){
    19. break;
    20. }
    21. }
    22. msgctl(msqid, IPC_RMID, NULL);
    23. return 0;
    24. }

    接受方:

    1. #include "myhead.h"
    2. int main(int argc, char const *argv[])
    3. {
    4. key_t key;
    5. int msgqid;
    6. msg_t msg;
    7. if ((key = ftok("/home/linux",'r')) == -1){
    8. PRINT_ERR("ftok error");
    9. }
    10. if ((msgqid = msgget(key, IPC_CREAT|0666)) == -1){
    11. PRINT_ERR("msgget error");
    12. }
    13. while (1){
    14. memset(msg.text, 0, sizeof(msg.text));
    15. msgrcv(msgqid, &msg, MSGSIZE,0,0);
    16. if (!strncmp("quit",msg.text,4)){
    17. break;
    18. }
    19. printf("%s\n",msg.text);
    20. }
    21. msgctl(msgqid,IPC_RMID,NULL);
    22. return 0;
    23. }

    4.3.4消息队列的实例:(关注类型的)

    头文件:

    1. #ifndef __MSGQUE_H__
    2. #define __MSGQUE_H__
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. typedef struct msgbuf {
    12. long id;
    13. char name[30];
    14. char sex;
    15. int age;
    16. }msg_t;
    17. #define MSGSIZE (sizeof(msg_t)-sizeof(long))
    18. #endif

    发送方:

    1. #include "msgqueue.h"
    2. #include
    3. int main(int argc, const char* argv[])
    4. {
    5. key_t key;
    6. int msqid;
    7. if ((key = ftok("/home/linux/", 'r')) == -1)
    8. PRINT_ERR("ftok get key error");
    9. if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1)
    10. PRINT_ERR("create msg queue error");
    11. msg_t m1 = {
    12. .id = 1,
    13. .name = "zhangsan",
    14. .sex = 'm',
    15. .age = 30,
    16. };
    17. msgsnd(msqid, &m1, MSGSIZE, 0);
    18. msg_t m2 = {
    19. .id = 2,
    20. .name = "lisi",
    21. .sex = 'w',
    22. .age = 18,
    23. };
    24. msgsnd(msqid, &m2, MSGSIZE, 0);
    25. msg_t m3 = {
    26. .id = 3,
    27. .name = "wangwu",
    28. .sex = 'm',
    29. .age = 22,
    30. };
    31. msgsnd(msqid, &m3, MSGSIZE, 0);
    32. // msgctl(msqid, IPC_RMID, NULL);
    33. return 0;
    34. }

    接受方:

    1. #include "msgqueue.h"
    2. int main(int argc, const char* argv[])
    3. {
    4. key_t key;
    5. int msqid;
    6. msg_t msg;
    7. if ((key = ftok("/home/linux/", 'r')) == -1)
    8. PRINT_ERR("ftok get key error");
    9. if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1)
    10. PRINT_ERR("create msg queue error");
    11. memset(&msg, 0, sizeof msg);
    12. msgrcv(msqid, &msg, MSGSIZE, atoi(argv[1]), 0);
    13. printf("id=%ld,name=%s,sec=%c,age=%d\n",msg.id,msg.name,msg.sex,msg.age);
    14. // msgctl(msqid, IPC_RMID, NULL);
    15. return 0;
    16. }

    结果图:

     4.4共享内存:

    4.4.1原理:

    共享内存:在内核空间创建共享内存,让用户的A和B进程都能够访问到。通过这块内存

    进行数据的传递。共享内存所有的进程间通信中效率最高的方式(不需要来回拷贝数据),共享内存的大小为 4k整数倍

    4.4.2实例:

    接受方:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define PRINT_ERR(msg) do{\
    8. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    9. printf(msg);\
    10. exit(-1); \
    11. }while(0)
    12. int main(int argc, char const *argv[])
    13. {
    14. key_t key;
    15. int shmid;
    16. char* over;
    17. if ((key = ftok("/home/linux", 'r')) == -1){
    18. PRINT_ERR("ftok error");
    19. }
    20. if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){
    21. PRINT_ERR("shemget error");
    22. }
    23. if ((over = shmat(shmid, NULL, 0)) == (void*)-1){
    24. PRINT_ERR("shmat error");
    25. }
    26. while (1){
    27. if (!strncmp("quit", over, 4))break;
    28. getchar();
    29. printf("%s\n",over);
    30. }
    31. if (shmdt(over)){
    32. PRINT_ERR("shmdt error");
    33. }
    34. shmctl(shmid,IPC_RMID,NULL);
    35. return 0;
    36. }

    发送方:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define PRINT_ERR(msg) do{\
    8. printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    9. printf(msg);\
    10. exit(-1); \
    11. }while(0)
    12. int main(int argc, char const *argv[])
    13. {
    14. key_t key;
    15. int shmid;
    16. char* over;
    17. if ((key = ftok("/home/linux", 'r')) == -1){
    18. PRINT_ERR("ftok error");
    19. }
    20. if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){
    21. PRINT_ERR("shmget error\n");
    22. }
    23. if ((over = shmat(shmid, NULL, 0)) == (void*)-1){
    24. PRINT_ERR("shmat error\n");
    25. }
    26. while (1){
    27. printf("请输入>>");
    28. fgets(over,4096,stdin);
    29. over[strlen(over) - 1] = '\0';
    30. if (!strncmp("quit",over,4)){
    31. break;
    32. }
    33. }
    34. if (shmdt(over)){
    35. PRINT_ERR("shmdt error\n");
    36. }
    37. shmctl(shmid,IPC_RMID,NULL);
    38. return 0;
    39. }

    4.5信号灯集合

    4.1信号量的原理

    信号量:又叫信号灯集,它是实现进程间同步的机制。在一个信号灯集中可以有

    很多的信号灯,这些信号灯它们的工作相关不干扰。一般使用的时候使用的是二值

    信号灯。

    4.2信号灯集函数的封装

    sem.h

    1. #ifndef __SEM_H__
    2. #define __SEM_H__
    3. int mysem_init(int nsems);
    4. int P(int semid, int semnum);
    5. int V(int semid, int semnum);
    6. int sem_del(int semid);
    7. #endif

    sem.c

    1. #include
    2. union semun {
    3. int val; /* Value for SETVAL */
    4. struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */
    5. };
    6. int semnum_init_value(int semid, int which, int value)
    7. {
    8. union semun sem = {
    9. .val = value,
    10. };
    11. if (semctl(semid, which, SETVAL, sem) == -1)
    12. PRINT_ERR("semctl int value error");
    13. return 0;
    14. }
    15. //初始化信号灯集
    16. int mysem_init(int nsems)
    17. {
    18. key_t key;
    19. int semid;
    20. // 1.通过ftok获取键值
    21. if ((key = ftok("/home/linux/", 'g')) == -1)
    22. PRINT_ERR("get key error");
    23. // 2.如果不选择就创建信号灯集,如果存在返回已存在的错误
    24. if ((semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
    25. if (errno == EEXIST) {
    26. //如果已存在,这里调用semget,直接返回semid
    27. semid = semget(key, nsems, IPC_CREAT | 0666);
    28. } else {
    29. PRINT_ERR("create sem error");
    30. }
    31. } else {
    32. // 3.初始化信号灯集中的信号灯
    33. for (int i = 0; i < nsems; i++) {
    34. semnum_init_value(semid, i, !i);
    35. }
    36. }
    37. return semid;
    38. }
    39. //申请资源
    40. int P(int semid, int semnum)
    41. {
    42. struct sembuf buf = {
    43. .sem_num = semnum,
    44. .sem_op = -1,
    45. .sem_flg = 0,
    46. };
    47. if (semop(semid, &buf, 1))
    48. PRINT_ERR("request resource error");
    49. return 0;
    50. }
    51. //释放资源
    52. int V(int semid, int semnum)
    53. {
    54. struct sembuf buf = {
    55. .sem_num = semnum,
    56. .sem_op = 1,
    57. .sem_flg = 0,
    58. };
    59. if (semop(semid, &buf, 1))
    60. PRINT_ERR("free resource error");
    61. return 0;
    62. }
    63. //删除信号灯集
    64. int sem_del(int semid)
    65. {
    66. semctl(semid,0,IPC_RMID);
    67. }

    4.3用信号灯集实现进程同步

    写端:

    1. #include
    2. #include "sem.h"
    3. int main(int argc, const char* argv[])
    4. {
    5. key_t key;
    6. int shmid,semid;
    7. char* waddr;
    8. //0.信号量的初始化
    9. semid = mysem_init(2);
    10. if(semid == -1){
    11. printf("sem init error");
    12. return -1;
    13. }
    14. // 1.获取key
    15. if ((key = ftok("/home/linux", 'p')) == -1)
    16. PRINT_ERR("get key error");
    17. // 2.创建共享内存
    18. if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1)
    19. PRINT_ERR("create share memory error");
    20. // 3.将共享内存映射到用户空间
    21. if ((waddr = shmat(shmid, NULL, 0)) == (void*)-1)
    22. PRINT_ERR("shmat error");
    23. printf("waddr = %p\n", waddr);
    24. // 4.写操作
    25. while (1) {
    26. P(semid,0);
    27. printf("input > ");
    28. fgets(waddr, 4096, stdin);
    29. waddr[strlen(waddr) - 1] = '\0';
    30. if (strncmp(waddr, "quit", 4) == 0)
    31. break;
    32. V(semid,1);
    33. }
    34. // 5.取消地址映射
    35. if (shmdt(waddr))
    36. PRINT_ERR("shmdt error");
    37. // 6.删除共享内存
    38. if (shmctl(shmid, IPC_RMID, NULL))
    39. PRINT_ERR("shmrm error");
    40. //7.删除信号量
    41. sem_del(semid);
    42. return 0;
    43. }

    读端口:

    1. #include "sem.h"
    2. #include
    3. int main(int argc, const char* argv[])
    4. {
    5. key_t key;
    6. int shmid, semid;
    7. char* raddr;
    8. // 0.信号量的初始化
    9. semid = mysem_init(2);
    10. if (semid == -1) {
    11. printf("sem init error");
    12. return -1;
    13. }
    14. // 1.获取key
    15. if ((key = ftok("/home/linux", 'p')) == -1)
    16. PRINT_ERR("get key error");
    17. // 2.创建共享内存
    18. if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1)
    19. PRINT_ERR("create share memory error");
    20. // 3.将共享内存映射到用户空间
    21. if ((raddr = shmat(shmid, NULL, 0)) == (void*)-1)
    22. PRINT_ERR("shmat error");
    23. printf("waddr = %p\n", raddr);
    24. // 4.读操作
    25. while (1) {
    26. P(semid,1);
    27. printf("raddr = %s\n", raddr);
    28. if (strncmp(raddr, "quit", 4) == 0)
    29. break;
    30. V(semid,0);
    31. }
    32. // 5.取消地址映射
    33. if (shmdt(raddr))
    34. PRINT_ERR("shmdt error");
    35. // 6.删除共享内存
    36. shmctl(shmid, IPC_RMID, NULL);
    37. //7.删除信号量
    38. sem_del(semid);
    39. return 0;
    40. }

  • 相关阅读:
    【Linux内核代码分析1】Linux时间子系统及HRTIMER实现
    【如何在Ubuntu 20.04系统上安装和使用Wine教程】
    堆排序--C语言版
    PX4模块设计之三十七:MulticopterRateControl模块
    基于SSM的校园车辆管理系统设计与实现
    程序员,在北上广深杭赚够100万,就逃回二三四线城市生活,靠谱吗?
    Pr:导出设置之音频
    nuxt.js服务端渲染项目性能优化总结
    Qt入门学习及GUI编程基础教程
    Docker的入门基础和使用
  • 原文地址:https://blog.csdn.net/a2998658795/article/details/126328709