linux系统编程之多进程和管道(pip)

822 阅读2分钟

管道一般用于linux程序进程间通信

创建进程

fork()函数

#include <stdio.h>

void main()
{
    if (fork())
      printf("PARENT\n");                                                                                                         
    else
      printf("CHILD\n");
}

fork()执行后,当前进程将被复制出一个新的进程,返回值非0表示仍在父进程执行,返回0表示程序执行已进入子进程内,执行效果参考如下 -w705 可以看到父子进程的代码都被执行了

父进程等待子进程执行完成

wait()

执行fork()后生成了子进程,如果需要在父进程中等待子进程执行完成,比如子进程下载文件,下载完成后父进程需要使用这个文件,可以使用wait()函数等待子进程执行完成

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int status;
  if (fork()) {
    printf("parent waiting for child ...\n");
    wait(&status);
    if (WIFEXITED(status))
      printf("child ended normally, exit status = %d\n", WEXITSTATUS(status));
    if (WIFSIGNALED(status))
      printf("child terminated by signal %d\n", WTERMSIG(status));
  } else {
    printf("child running -- PID is %d\n", getpid());                                                                             
    sleep(5);
    exit(3);
  }
}

执行效果参考如下 -w510 可以看到父进程等到了子进程退出,并获得了子进程退出代码值3

匿名管道

-w339

pip()

管道端点

  • 0是读取端
  • 1是写入端
#include <stdio.h>
#include <string.h>

void main()
{
    int p[2];
    pipe(p);

    if (fork() == 0) { // 子进程写入数据
        // 关闭管道读取端
            close(p[0]);
        char* str1 = "a string write to pip";
        write(p[1], str1, strlen(str1)+1);
        close(p[1]);
    } else { // 父进程读取数据
        // 关闭管道写入端
        close(p[1]);
        char str2[100];
        read(p[0], str2, 100);
        close(p[0]);
        printf("read a string from pip: %s\n", str2);
    }
}

执行效果参考如下 -w507

命名管道

mkfifo()

可以使用mkfifo函数创建一个使用文件表示的管道,读写数据使用这个文件名即可

#include <stdio.h>
#include <string.h>
#include <fcntl.h>

void main()
{
    char * myfifo = "/tmp/myfifo";
    mkfifo(myfifo, 0666);

    if (fork() == 0) { // 子进程写入数据
        int fd = open(myfifo, O_WRONLY);
        char* str1 = "a string write to pip";
        write(fd, str1, strlen(str1)+1);
        close(fd);
    } else { // 父进程读取数据
        int fd = open(myfifo, O_RDONLY);
        char str2[100];
        read(fd, str2, sizeof(str2));
        printf("read a string from pip: %s\n", str2);
        close(fd);
    }
}

执行效果参考如下 -w545 可以看到,通过管道文件名就可以读取数据了

一些注意的点

linux默认的进程调度是没有固定顺序的,父进程和子进程同时执行的代码没有先后顺序之分

文件描述符

  • 0是标准输入
  • 1是标准输出