进程间通信

1、管道方式
1)无名管道:(只能在有亲缘关系的进程间进行通信)

#include<stdio.h>
#include<unistd.h>
int main(){
    int fd[2];
    if(pipe(fd)<0){
        printf("创建管道失败\n");
        return -1;
    }
    // fd[0] 用于输入
    // fd[1] 用于输出

    int pid = fork();  // 创建一个子进程
    if(pid<0){
        printf("创建子进程失败\n");
        return -1;
    } else if(pid==0){ // 子进程中
        write(fd[1], "hello", sizeof("hello"));
    } else {           // 父进程中
        char msg[8];
        read(fd[0], msg, sizeof(msg)-1);
        printf("父进程收到消息:%s\n", msg);
    }
    return 0;
}

2)有名管道(如果知道管道名称,可以支持在不同进程中的通信)
创建、写

#include<stdio.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(){
    const char *fifo_name = "./hchlqlz";

    if(access(fifo_name, F_OK)==-1){  // 判断该管道是否存在
        // access函数用于判断当前用户对文件的权限,功能取决于第二个参数
        // R_OK, W_OK, X_OK ,是否可读, 可写, 可执行
        // F_OK,文件是否存在

        if(mkfifo(fifo_name, 0666)==-1){
            printf("创建管道失败\n");
            return -1;
        }
    }

    int fid = open(fifo_name, O_WRONLY);  // 以只写的方式打开文件
    write(fid, "hello", sizeof("hello"));
    close(fid);


    return 0;
}

#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
int main(){
    const char *fifo_name = "./hchlqlz";
    int fid = open(fifo_name, O_RDONLY);
    char msg[8];
    read(fid, msg, sizeof(msg)-1);
    close(fid);
    printf("%s\n", msg);
    return 0;
}

注:打开管道时必须同时有读数据进程和写数据进程,缺了某一个,就会阻塞。
2、信号(signal)

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

bool ing = true;

void stop(int sig){   // sig:收到的信号
    ing = false;
}

int main(){

    signal(2, stop);  // 将信号2与stop函数绑定,如果接收到信号2,则调用stop函数

    while(ing){
        printf("!");
        fflush(NULL); // 刷新缓冲区
        sleep(1);     // 休眠1s
    }
    printf("结束运行\n");

    return 0;
}

3、消息队列

主要函数:

1)int msgget(key_t, key, int msgflg)
key:消息队列的key
msgflg:权限,可以异或IPC_CREAT、IPC_EXCL(如果不存在该消息队列,返回-1)

2)int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg)
msgid:消息队列id
msg_ptr:指向一个消息的指针,消息结构需要以一个long 作为开始,可以附加其他的信息
msg_sz:消息大小
msgflg:当队列满时进行的操作,0为阻塞,IPC_NOWAIT返回-1

3)int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg)
msgtype:指定获取的消息,0:获取队列第一条消息,>0:获取指定类型的第一条消息,<0:获取类型<=msgtype绝对值的第一条消息

4)int msgctl(int msgid, int command, struct msgid_ds *buf)
command:执行的操作,IPC_RMID删除消息队列,IPC_STAT,设置buf,IPC_SET,用buf 设置消息队列的关联值

#include<stdio.h>
#include<string.h>
#include<sys/msg.h>

struct MSG{
    long type;
    char msg[128];
};

int main(){

    int qid = msgget(1, 0666 | IPC_CREAT);
    if(qid==-1){
        printf("获取消息队列失败\n");
        return -1;
    }

    MSG s1;
    s1.type = 1;
    strcpy(s1.msg, "hello1");
    msgsnd(qid, &s1, sizeof(s1), 0);

    MSG s2;
    s2.type = 3;
    strcpy(s2.msg, "hello3");
    msgsnd(qid, &s2, sizeof(s2), 0);

    MSG s3;
    msgrcv(qid, &s3, sizeof(s3), 3, 0);

    printf("从消息队列中取到的消息是:%s\n", s3.msg);

    msgctl(qid, IPC_RMID, 0);
    return 0;
}

4、共享内存
1)int shmget(key_t key, size_t size, int shmflg)
比消息队列的msgget多了一个size表示共享内存的大小。

2)void *shmat(int shm_id, const void *shm_addr, int shmflg)
刚获取到的共享内存,不能立即投入使用,需要用shmat函数来启动对该共享内存的访问,把共享内存连接到当前进程的地址空间上。
id:标识
addr:连接到当前进程的地址位置,为NULL时由系统进行选择

3)int shmdt(const void *shmaddr)
分离共享内存。

4)int shmctl(int shm_id, int command, struct shmid_ds *buf)
对共享内存进行操控。和消息队列类似

创建并写

#include<stdio.h>
#include<string.h>
#include<sys/shm.h>

struct Student{
    char name[16];
    char note[128];
};

int main(){

    int sid = shmget(520, sizeof(Student), 0666|IPC_CREAT);

    void *addr = shmat(sid, NULL, 0);

    Student* stu = (Student *)addr;
    strcpy(stu->name, "hchlqlz");
    strcpy(stu->note, "AC是我的梦想");

    shmdt(addr);

    return 0;
}

读并删除

#include<stdio.h>
#include<sys/shm.h>

struct Student{
    char name[16];
    char note[128];
};

int main(){

    int sid = shmget(520, sizeof(Student), 0666);

    void* addr = shmat(sid, NULL, 0);

    Student* stu = (Student*) addr;

    printf("学生姓名:%s\n", stu->name);
    printf("学生备注:%s\n", stu->note);

    shmdt(addr);

    shmctl(sid, IPC_RMID, 0);   

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值