C++多线程项目 - 进程间通信实现(一)

匿名管道

这里利用的是读时共享的策略,因为只有读操作时,子进程是共享父进程的资源,那么我们进行这样的操作

  • 创建子进程之前,创建一个管道
  • 子、父进程往管道写内容,子、父进程从管道读内容,这样就实现了信息传递

这里我有个疑问,写时拷贝,为什么管道不会复制? 找了很多资料,无果,暂时搁浅吧。

  1. 方法1 - linux命令
ls | wc -l
# ls 显示目录下的文件,包含目录
# | 管道符号
# wc -l 统计行号
# ls 显示文件列表
  1. 方法2 - 代码
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
int main(){

    // pipe two ends
    int pipefd[2];

    // create pipe
    if(pipe(pipefd) == -1){
        perror("pipe");
        exit(0);
    }
    int ret = fork();
    if(ret == 0){
        // son process
        // wait father write data
        sleep(1);
        char buf [1024];
        
        // read data from pipe write to buf, and return the len of read data
        int len = read(pipefd[0], &buf, 1024);
        
        printf("%d %s\n", len, buf);
        close(pipefd[0]);
    } else if(ret == -1){
        perror("fork");
        exit(0);
    } else {
        // father
        // write data
        write(pipefd[1], "hello tiffany!\n", 16);
        close(pipefd[1]);
    }
} 

有名管道

匿名管道仅仅局限于有亲属关系的进程当中。
在任意两个进程间进行管道通信,需要使用有名管道。

  1. 方法1 - 命令行
mkfifo afifo
# 不知道怎么使用,基于命令行
  1. 方法2 - 代码
// create fifo
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
    
    int ret = mkfifo("afifo", 0664);
    if(ret == -1){
        perror("mkfifo");
        exit(0);
    }
}
// write to pipe
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(){
    int fd = open("afifo", O_WRONLY);
    if(fd == -1){
        perror("fifo");
        exit(0);
    }
    char buf[1024];
    sprintf(buf, "hello ethan\n");
    write(fd, buf, strlen(buf));
    printf("write: %s\n", buf);
    return 0;
}
// read from fifo
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
int main(){
    int fd = open("afifo", O_RDONLY);
    if(fd == -1){
        perror("fifo");
        exit(0);
    }
    char readBuff[1024];
    int len = read(fd, readBuff, 1024);
    printf("read: %s\n", readBuff);
    return 0;
}

tips: when we only open fifo by O_WRONLY, the fifo will be blocked, untill the one process open it by O_RDONLY or O_RDWR.
so,

  • run create process, fifo named afifo will be created;
  • run write process, the process will be blocked;
  • run read process, write and read will be succsessfully completed.

匿名内存映射

原理,将一个文件映射到一块内存,相当于开辟了一块内存,两个进程先后的访问这块内存,相当于把这块内存当作中转站,即可实现共享。匿名,内存的首地址在创建子进程之前,所以子进程能共享该内存指针


#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <wait.h>

int main(){
    // open a file to mmap
    int fd = open("test.txt", O_RDWR);
    int size = lseek(fd, 0, SEEK_END);

    // create a memory map area
    void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    if(ptr == MAP_FAILED){
        perror("mmap");
        exit(0);
    }
    pid_t pid = fork();
    if(pid > 0){
        wait(NULL);// wait for recycle process by blocked
        char buf [1024];
        strcpy(buf, (char *)ptr);
        printf("read data: %s\n", buf);
    } else if(pid == 0){
        // child process
        strcpy((char *)ptr, "nihao nina tiffany\n");
    }

    // close memory map area
    munmap(ptr, size);
}

内存映射

// write.cpp
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){

    // 1. open a file
    int fd = open("test.txt", O_RDWR);
    
    // 2. mmap
    void* ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    getchar();

    // 3. write data
    strcpy((char *)ptr, "hello nihao");

    // 4. unmap and close fd
    munmap(ptr, 1024);
    close(fd);

    return 0;
}
// read.cpp
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(){

    // 1. open a file
    int fd = open("test.txt", O_RDWR);
    
    // 2. mmap
    void* ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    // 3. read data
    printf("%s", (char *)ptr);

    getchar();

    printf("%s", (char *)ptr);
    // 4. unmap and close fd
    munmap(ptr, 1024);
    close(fd);

    return 0;
}

共享内存

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


int main(){
    
    // 1. create a shm
    int shmid = shmget(100, 1024, IPC_CREAT | 0664);
    
    // 2. let the shm associate with current process
    void* ptr = shmat(shmid, NULL, 0);


    // 3. write data
    const char* str = "hello ethan";

    memcpy(ptr, str, strlen(str) + 1);
    printf("%s", (char *)ptr);

    getchar();

    // 4. detach the association
    shmdt(ptr);

    // 5. delete the shm
    shmctl(shmid, IPC_RMID, NULL);
}
// read
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>


int main(){
    
    // 1. create a shm
    int shmid = shmget(100, 1024, IPC_CREAT);
    
    // 2. let the shm associate with current process
    void* ptr = shmat(shmid, NULL, 0);


    // 3. read data
    getchar();
    printf("%s", (char*)ptr);

    // 4. detach the association
    shmdt(ptr);

    // 5. delete the shm
    shmctl(shmid, IPC_RMID, NULL);
}

内存映射与共享内存比较

  1. 内存映射无大小限制,共享内存大小小于主存的大小
  2. 内存映射与实际的文件关联,共享内存无关联
  3. 当程序异常终止,内存映射的文件可能保存在文件中, 当共享内存无了
  4. 内存映射可能涉及到磁盘读写,速度慢于共享内存
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值