C语言中进程间通讯的方式详解

2022-08-18 16:46:56
目录
一.无名管道1.1无名管道的原理1.2功能1.3无名管道通信特点1.4无名管道的实例二.有名管道2.1有名管道的原理2.2有名管道的特点2.3有名管道实例三.信号3.1信号的概念3.2发送信号的函数3.3常用的信号3.4实例四.IPC进程间通信4.1IPC进程间通信的种类4.2查看IPC进程间通信的命令4.3消息队列4.4共享内存4.5信号灯集合

一.无名管道

1.1无名管道的原理

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

1.2功能

1)>

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

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

1.3无名管道通信特点

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

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

单工>

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

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

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

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

5.读写的特点

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

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

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

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

1.4无名管道的实例

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h> 
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define ERROR(msg) do{\
    printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    printf(msg);\
    exit(-1); \
}while(0)
 
int main(int argc, char const *argv[])
{
    pid_t pid;
    int num[2];
    char buff[128] = {0};
 
    if (pipe(num)){
        ERROR("pipe error");
    }
 
    if ((pid = fork()) == -1){
        ERROR("fork error");
    }else if(pid == 0){
        close(num[0]);
        while (1){
            memset(buff, 0, sizeof(buff));
            printf("请输入您要输入的数值>>");
            fgets(buff, sizeof(buff), stdin);
            buff[strlen(buff) -1] = '\0';
            write(num[1], buff, strlen(buff));
 
            if (!strncmp(buff, "quit", 4)){
                break;
            }
 
        }
        close(num[1]);
        exit(EXIT_SUCCESS);
    }else{
        close(num[1]);
        while (1){
            memset(buff, 0, sizeof(buff));
            read(num[0], buff, sizeof(buff));
 
            if (!strncmp(buff, "quit", 4)){
                break;
            }
            printf("%s\n",buff);
        }   
        close(num[0]);
        wait(NULL);
    }
 
    return 0;
}

二.有名管道

2.1有名管道的原理

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

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

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

2.2有名管道的特点

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

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

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

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

5.读写的特点

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

如果读端不存写管道

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

2.读端打开后关闭,管道破裂(SIGPIPE)>

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

如果写端不存在读管道

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

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

2.3有名管道实例

mkfifo文件:

#include <stdio.h>
#include <stdlib.h>
#define ERROR(msg) do{\
    printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    printf(msg);\
    exit(-1); \
}while(0)
 
int main(int argc, char const *argv[])
{
    if (mkfifo("./fifo",0666)){
        ERROR("mkfifo error");
    }
 
    //有名管道没有阻塞,手动加一个阻塞
    getchar();
 
    system("rm ./fifo -rf");
    
    return 0;
}

write文件:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
 
#define ERROR(msg) do{\
    printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
    printf(msg);\
    exit(-1); \
}while(0)
 
int main(int argc, char const *argv[])
{
    int fd;
    char buff[128] = {0};
    if ((fd = open("./fifo",O_WRONLY)) == -1){
        ERROR("open fifo error\n");
    }
 
    while(1){
        printf("input >");
        fgets(buff, sizeof(buff), stdin);
        buff[strlen(buff) - 1] = '\0';
 
        write(fd, buff, strlen(buff));
        if(!strncmp("quit",buff,4))break;
    }
    close(fd);
    return 0;
}

read文件:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
 
#define ERROR(msg)                                          \
    do                                                      \
    {                                                       \
        printf("%s %s %d\n", __FILE__, __func__, __LINE__); \
        printf(msg);                                        \
        exit(-1);                                           \
    } while (0)
 
int main(int argc, char const *argv[])
{
    int fd;
    char buff[128] = {0};
    if ((fd = open("./fifo", O_RDONLY)) == -1)
    {
        ERROR("open error");
    }
 
    while (1){
        memset(buff, 0, sizeof(buff));
        read(fd, buff, sizeof(buff));
        if (!strncmp("quit",buff,4)){
            break;
        }
 
        printf("%s\n",buff);
    }
    close(fd);
    return 0;
}

三.信号

3.1信号的概念

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

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

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

3.2发送信号的函数

int>

功能:给自己(进程或者线程)发信号

参数:

@sig:信号号

返回值:成功返回0,失败返回非0

int kill(pid_t pid, int sig);

功能:给进程发信号

参数:

@pid:进程号

    pid > 0 :给pid对应的进程发信号pid = 0 :给同组的进程发信号pid = -1:给所有的有权限操作的进程发送信号,init进程除外pid < -1:给-pid对应的同组的进程发信号       

    @sig:信号号

    返回值:成功返回0,失败返回-1置位错误码  

    3.3常用的信号

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

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

    3.4实例

    捕捉ctrl+c

    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #define ERROR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    void handle(int num)
    {
        if (num == SIGINT){
            printf("我收到一个ctrl+c的信号\n");
        }
    }
     
    int main(int argc, char const *argv[])
    {
        //捕捉
        if (signal(SIGINT, handle) == SIG_ERR){
            ERROR("register signal error");
        }
        //忽略
        if (signal(SIGINT,SIG_IGN) == SIG_ERR){
            ERROR("register signal error");
        }
        //默认
        if (signal(SIGINT,SIG_DFL) == SIG_ERR){
            ERROR("register signale");
        }
     
     
        while(1);
        return 0;
    }

    捕捉管道破裂的消息

    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
     
    #define ERROR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    void handle(int num)
    {
        if (num == SIGPIPE){
            printf("捕捉到一条管道破裂的消息\n");
        }
    }
     
    int main(int argc, char const *argv[])
    {
        int num[2];
        char buff[32] = "123";
     
        if(pipe(num)){
            ERROR("pipe error");
        }
     
        if (signal(SIGPIPE,handle) == SIG_ERR){
            ERROR("signal error");
        }
     
        close(num[0]);
     
        write(num[1],buff,strlen(buff));
        return 0;
    }

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

    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
     
    void signal_handle(int signo)
    {
        printf("我是父进程,收到了子进程退出的信号,为它回收资源\n");
        waitpid(-1,NULL,WNOHANG); //非阻塞方式回收资源
        printf("为子进程回收资源成功\n");
        raise(SIGKILL);  //给父进程发送信号,结束父进程
    }
     
    int main(int argc,const char * argv[])
    {
        pid_t pid;
     
        pid = fork();
        if(pid == -1){
            ERROR("fork error");
        }else if(pid == 0){
            sleep(5);
            printf("子进程执行结束了\n");
            exit(EXIT_SUCCESS);
        }else{
            if(signal(SIGCHLD,signal_handle)==SIG_ERR)
                ERROR("signal error");
     
            while(1);
        }
        
        return 0;
    }

    用arlarm实现一个斗地主机制

    #include <stdio.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>
     
    #define ERROR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    void handle(int num)
    {
        if (num == SIGALRM){
            printf("自动出牌\n");
        }
        alarm(3);
    }
     
    int main(int argc, char const *argv[])
    {
        char ch;
        if (signal(SIGALRM,handle) == SIG_ERR){
            ERROR("signale error");
        }
        
        alarm(3);
     
        while (1){
            printf("请输入您要出的牌>>");
            ch = getchar();
            getchar();
            printf("%c\n",ch);
            alarm(3);
        }
        return 0;
    }

    四.IPC进程间通信

    4.1IPC进程间通信的种类

    (1)消息队列

    (2)共享内存

    (3)信号灯集

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

    4.2.1查看

    ipcs>

    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进程间通信键值的获取

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdlib.h>
     
    #define ERROR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    int main(int argc, char const *argv[])
    {
        key_t key;
        struct stat st;
     
       if ((key = ftok("/home/linux",'w')) == -1){
            ERROR("ftok error");
       }
     
       printf("key=%#x\n",key);
     
       if (stat("/home/linux",&st)){
            ERROR("stat error");
       }
     
       printf("pro_id=%#x,devno=%#lx,ino=#=%#lx\n",'w',st.st_dev,st.st_ino);
        return 0;
    }

    结果图:

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

    头文件:

    #ifndef __MYHEAD_H__
    #define __MYHEAD_H__
     
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/msg.h>
    #include <string.h>
     
    #define  PRINT_ERR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
     
    #define MSGSIZE (sizeof(msg_t)-sizeof(long))
     
    typedef  struct mubuf{
        long mtype;
        char text[512];
    }msg_t;
     
    #endif

    发送方:

    #include "myhead.h"
     
    int main(int argc, char const *argv[])
    {
        key_t key;
        int msqid;
        msg_t msg ={
            .mtype = 100,
        };
     
         if((key = ftok("/home/linux/",'r'))==-1)
            PRINT_ERR("ftok get key error");
     
        if((msqid = msgget(key,IPC_CREAT|0666))==-1)
            PRINT_ERR("create msg queue error");
     
        while (1){
            memset(msg.text,0,sizeof(msg.text));
            fgets(msg.text,MSGSIZE,stdin);
            msg.text[strlen(msg.text) - 1] = '\0';
     
            msgsnd(msqid, &msg, MSGSIZE, 0);
     
            if (!strncmp(msg.text,"quit",4)){
                break;
            }
        }
     
        msgctl(msqid, IPC_RMID, NULL);
        return 0;
    }

    接受方:

    #include "myhead.h"
     
    int main(int argc, char const *argv[])
    {
        key_t key;
        int msgqid;
        msg_t msg;
     
        if ((key = ftok("/home/linux",'r')) == -1){
            PRINT_ERR("ftok error");
        }
     
        if ((msgqid = msgget(key, IPC_CREAT|0666)) == -1){
            PRINT_ERR("msgget error");
        }
     
        while (1){
            memset(msg.text, 0, sizeof(msg.text));
            msgrcv(msgqid, &msg, MSGSIZE,0,0);
     
            if (!strncmp("quit",msg.text,4)){
                break;
            }
     
            printf("%s\n",msg.text);
        }
     
        msgctl(msgqid,IPC_RMID,NULL);
        return 0;
    }
    

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

    头文件:

    #ifndef __MSGQUE_H__
    #define __MSGQUE_H__
     
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/msg.h>
    #include <string.h>
     
    typedef struct msgbuf {
        long id;
        char name[30];
        char sex;
        int age;
    }msg_t;
     
    #define MSGSIZE (sizeof(msg_t)-sizeof(long))
     
    #endif

    发送方:

    #include "msgqueue.h"
    #include <head.h>
     
    int main(int argc, const char* argv[])
    {
        key_t key;
        int msqid;
     
        if ((key = ftok("/home/linux/", 'r')) == -1)
            PRINT_ERR("ftok get key error");
     
        if ((msqid = msgget(key, IPC_CREAT | 0666)) == -1)
            PRINT_ERR("create msg queue error");
     
        msg_t m1 = {
            .id = 1,
            .name = "zhangsan",
            .sex = 'm',
            .age = 30,
        };
        msgsnd(msqid, &m1, MSGSIZE, 0);
        msg_t m2 = {
            .id = 2,
            .name = "lisi",
            .sex = 'w',
            .age = 18,
        };
        msgsnd(msqid, &m2, MSGSIZE, 0);
        msg_t m3 = {
            .id = 3,
            .name = "wangwu",
            .sex = 'm',
            .age = 22,
        };
        msgsnd(msqid, &m3, MSGSIZE, 0);
     
     
        // msgctl(msqid, IPC_RMID, NULL);
     
        return 0;
    }

    接受方:

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

    结果图:

    4.4共享内存

    4.4.1原理:

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

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

    4.4.2实例

    接受方:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    #include <stdlib.h>
     
    #define  PRINT_ERR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    int main(int argc, char const *argv[])
    {
        key_t key;
        int shmid;
        char* over;
     
        if ((key = ftok("/home/linux", 'r')) == -1){
            PRINT_ERR("ftok error");
        }
     
        if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){
            PRINT_ERR("shemget error");
        }
     
        if ((over = shmat(shmid, NULL, 0)) == (void*)-1){
            PRINT_ERR("shmat error");
        }
     
        while (1){
            if (!strncmp("quit", over, 4))break;
            getchar();
     
            printf("%s\n",over);
        }
     
        if (shmdt(over)){
            PRINT_ERR("shmdt error");
        }
     
        shmctl(shmid,IPC_RMID,NULL);
        return 0;
    }

    发送方:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    #include <stdlib.h>
     
    #define  PRINT_ERR(msg) do{\
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);\
        printf(msg);\
        exit(-1); \
    }while(0)
     
    int main(int argc, char const *argv[])
    {
        key_t key;
        int shmid;
        char* over;
     
        if ((key = ftok("/home/linux", 'r')) == -1){
            PRINT_ERR("ftok error");
        }
     
        if ((shmid = shmget(key, 4096, IPC_CREAT|0666)) == -1){
            PRINT_ERR("shmget error\n");
        }
     
        if ((over = shmat(shmid, NULL, 0)) == (void*)-1){
            PRINT_ERR("shmat error\n");
        }
     
        while (1){
            printf("请输入>>");
            fgets(over,4096,stdin);
            over[strlen(over) - 1] = '\0';
     
            if (!strncmp("quit",over,4)){
                break;
            }
        }
     
        if (shmdt(over)){
            PRINT_ERR("shmdt error\n");
        }
     
        shmctl(shmid,IPC_RMID,NULL);
        return 0;
    }

    4.5信号灯集合

    信号量的原理

    信号量:又叫信号灯集,它是实现进程间同步的机制。在一个信号灯集中可以有很多的信号灯,这些信号灯它们的工作相关不干扰。一般使用的时候使用的是二值信号灯。

    信号灯集函数的封装

    sem.h

    #ifndef __SEM_H__
    #define __SEM_H__
     
    int mysem_init(int nsems);
    int P(int semid, int semnum);
    int V(int semid, int semnum);
    int sem_del(int semid);
     
    #endif
    sem.c
    #include <head.h>
     
    union semun {
        int val; /* Value for SETVAL */
        struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */
    };
     
    int semnum_init_value(int semid, int which, int value)
    {
        union semun sem = {
            .val = value,
        };
        if (semctl(semid, which, SETVAL, sem) == -1)
            PRINT_ERR("semctl int value error");
        return 0;
    }
     
    //初始化信号灯集
    int mysem_init(int nsems)
    {
        key_t key;
        int semid;
        // 1.通过ftok获取键值
        if ((key = ftok("/home/linux/", 'g')) == -1)
            PRINT_ERR("get key error");
        // 2.如果不选择就创建信号灯集,如果存在返回已存在的错误
        if ((semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
            if (errno == EEXIST) {
                //如果已存在,这里调用semget,直接返回semid
                semid = semget(key, nsems, IPC_CREAT | 0666);
            } else {
                PRINT_ERR("create sem error");
            }
        } else {
            // 3.初始化信号灯集中的信号灯
            for (int i = 0; i < nsems; i++) {
                semnum_init_value(semid, i, !i);
            }
        }
     
        return semid;
    }
     
    //申请资源
    int P(int semid, int semnum)
    {
        struct sembuf buf = {
            .sem_num = semnum,
            .sem_op = -1,
            .sem_flg = 0,
        };
     
        if (semop(semid, &buf, 1))
            PRINT_ERR("request resource error");
     
        return 0;
    }
    //释放资源
    int V(int semid, int semnum)
    {
        struct sembuf buf = {
            .sem_num = semnum,
            .sem_op = 1,
            .sem_flg = 0,
        };
     
        if (semop(semid, &buf, 1))
            PRINT_ERR("free resource error");
     
        return 0;
    }
    //删除信号灯集
    int sem_del(int semid)
    {
        semctl(semid,0,IPC_RMID);
    }

    用信号灯集实现进程同步

    写端:

    #include <head.h>
    #include "sem.h"
     
    int main(int argc, const char* argv[])
    {
        key_t key;
        int shmid,semid;
        char* waddr;
        //0.信号量的初始化
        semid = mysem_init(2);
        if(semid == -1){
            printf("sem init error");
            return -1;
        }
        // 1.获取key
        if ((key = ftok("/home/linux", 'p')) == -1)
            PRINT_ERR("get key error");
        // 2.创建共享内存
        if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1)
            PRINT_ERR("create share memory error");
        // 3.将共享内存映射到用户空间
        if ((waddr = shmat(shmid, NULL, 0)) == (void*)-1)
            PRINT_ERR("shmat error");
        printf("waddr = %p\n", waddr);
        // 4.写操作
        while (1) {
            P(semid,0);
            printf("input > ");
            fgets(waddr, 4096, stdin);
            waddr[strlen(waddr) - 1] = '\0';
            if (strncmp(waddr, "quit", 4) == 0)
                break;
            V(semid,1);
        }
        // 5.取消地址映射
        if (shmdt(waddr))
            PRINT_ERR("shmdt error");
     
        // 6.删除共享内存
        if (shmctl(shmid, IPC_RMID, NULL))
            PRINT_ERR("shmrm error");
        //7.删除信号量
        sem_del(semid);
        return 0;
    }

    读端口:

    #include "sem.h"
    #include <head.h>
    int main(int argc, const char* argv[])
    {
        key_t key;
        int shmid, semid;
        char* raddr;
        // 0.信号量的初始化
        semid = mysem_init(2);
        if (semid == -1) {
            printf("sem init error");
            return -1;
        }
        // 1.获取key
        if ((key = ftok("/home/linux", 'p')) == -1)
            PRINT_ERR("get key error");
        // 2.创建共享内存
        if ((shmid = shmget(key, 4096, IPC_CREAT | 0666)) == -1)
            PRINT_ERR("create share memory error");
     
        // 3.将共享内存映射到用户空间
        if ((raddr = shmat(shmid, NULL, 0)) == (void*)-1)
            PRINT_ERR("shmat error");
     
        printf("waddr = %p\n", raddr);
        // 4.读操作
        while (1) {
            P(semid,1);
            printf("raddr = %s\n", raddr);
            if (strncmp(raddr, "quit", 4) == 0)
                break;
            V(semid,0);
        }
        // 5.取消地址映射
        if (shmdt(raddr))
            PRINT_ERR("shmdt error");
     
        // 6.删除共享内存
        shmctl(shmid, IPC_RMID, NULL);
     
        //7.删除信号量
        sem_del(semid);
        return 0;
    }

    以上就是C语言中进程间通讯的方式详解的详细内容,更多关于C语言进程通讯的资料请关注易采站长站其它相关文章!