多进程编程


1. 进程间通信


1. 管道


  • 如果要进行全双工通信,需要建立两个管道
  • 管道没有名字,传送的事无格式的字节流,大小受限制
  • 在include/linux/limits.h中规定 #define PIPE_BUF 4096, 也就是一次管道读写最多传送512字节
  • read(int _fd, void* buf, size_t _nbytes); //读成功返回实际读取的字节数,失败返回-1,读到末端返回0,读空管道会被阻塞

  • write(INT _fd, _const void* _buff, size_t _n);//每次写的内容都附加在管道末端。为了避免交叉写入,每次写入的数据小于PIPE_BUF的大小

  • 如果O_NONBLOCKO_NDELAY表示被清除时,出现设备忙的情况,write会导致进程阻塞,成功返回写入字节数
  • 如果设置了这两个标识当数据没有写入成功时直接返回-1

1.管道


  • pipe: 一种半双工通信方式,数据只能单向流动,只能在具有亲缘关系(父子进程关系)的进程间使用。
//创建管道
#include <unistd.h>
int pipe(int fd[2]);  //成功返回0,失败返回-1。fd[0]用来读,fd[1]用来写
  • 如果进程要读取管道中的数据,应该关闭fd[1],同理写关闭fd[0]
//实例
int fd[2];
if (pipe(fd)) {
    cerr << "create pipe failure" << endl;
    exit(1);
}

//读
char message[100];
close(fd[1]);
read(fd[0], message, sizeof(message));

//写
close(fd[0]);
write(fd[1], message, strlen(message)+1);
用管道联系标准设备

  • 子进程中调用exec函数是,不能共享文件描述符。可以讲子进程中的文件描述符重定向到标准输入,当新执行程序从标准输入获取数据时实际上是从父进程中获取输入数据。
  • dupdup2函数提供文件描述符复制功能
  • 复制的问键描述符回合原来的文件描述符共享同一个文件指针
//调用成功是返回一个oldfd文件描述符的副本,失败返回-1
#include <unistd.h>
int dup(int oldfd); //返回值为当前可用文件描述符的最小值
int dup2(int oldfd, int newfd); //返回值为newfd
//dup程序片段
pid  = fork();
if (pid == 0) {
    close(1); //关闭子进程的标准输出
    dup[fd[1]); //复制管道输入端到标准输出
    execv("exam", argv, environ);

//dup2程序片段
pid = fork();
if (pid == 0) {
    dup2(1, fd[1]); //关闭标准输出并复制管道输出端到标准输出
    execv("exame", argv, environ);
}

2.有名管道


  • named pipe: 同上,但是允许无亲缘关系进程间通信。
  • shell 下使用mknod namedpipe创建一个有名管道
  • 有名管道是一个设备文件
//创建又名管道
#include <sys/types.h>
#include <sys/stat.h>
int mknod(const char* path, mode_t mod, dev_t dev); //dev为设备值
int mkfifo(const char* path, mode_t mod);
//实例,具有亲缘关系的进程使用有名管道通信
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;

#define FIFO "/tmpt/fifo"  //临时文件

int main() {
    pid_t pid;
    char buffer[80];
    int fd;
    unlink(FIFO);  //如果该文件存在先删除此文件
    mkfifo(FIFO, 0744);
    if ((pid = fork())>0) {

    } else if (pid == 0) {

    } else {
        cerr << "fork" << endl;
        exit(1);
    }
    return 0;
}

3.扩展


  • POSIX2中用管道实现了简单的进程间通信函数popen()pclose();
FILE* popen(_const char* _command, _const char* _modes);
//该函数fork一个子进程,在子进程中执行第一个参数程序,同时返回文件指针(第一个参数指向要执行的命令的指针), 第二个参数表示I/O模式的类型
//实例
#include <limits.h>
#include <sring.h>

int main(int argc, char* argv[]) {
    FILE* finput, *foutput;    
    char* buffer(PIPE_BUF];
    int n;
    finput = popen("echo test!", "r");  //将echo test命令的输出与读端连接
    fouput = popen("cat", "w");    //将cat命令的输入与写端相连
    read(fileno(finput), buffer, strlen("test")); //读echo test而输出结果到buf
    write(fileno(foutput), buffer, strlen("test")); //将管道内容读出作为cat输入
    pclose(finput); //fileno(FILE*)是获得流的文件描述符(stdio.h)
    pclose(foutput);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值