一、fork 的用法
fork 返回值 c++
在C++中,fork
是一个来自 Unix/Linux 系统的系统调用,用于创建一个与现有进程几乎完全相同的新进程。fork
的主要特点是它会返回两次,一次返回在父进程中,一次返回在子进程中。在父进程中,fork
返回新创建子进程的进程ID;而在子进程中,fork
返回0。如果fork
失败,则在父进程中返回-1,并设置errno
。
以下是一个简单的C++示例,演示如何使用 fork
:
生成的结果如下:
二、什么是匿名管道
匿名管道是linux中一种非常古老的进程间通信方式,本质上就是一个内存级的文件。
一般用于父子进程间通信。概念上就是父进程与子进程共同使用一个管道文件来传输数据。
虽然父子进程都有对管道的读和写功能,但在使用时只能读或者写,因此管道是单向通信,半双工模式。
三.如何使用匿名管道
(一).pipe原理
参数是长度为2的整形数组,pipefd[0]代表读端文件描述符,pipefd[1]代表写端文件描述符。
返回值是int,创建成功返回0,失败返回-1,同时记录进errno。
pipe的使用原理上,就是首先父进程创建一个管道文件,但同时赋予管道文件两个文件描述符。
一个是以读方式打开即pipefd[0],另一个是以写方式打开即pipefd[1]。
(二).pipe使用
以下面代码为例:
父进程使用write接口将字符串给管道,子进程从管道中接收字符串并打印。
同时,子进程的read系统接口会阻塞,直到父进程往管道中写完数据,read一次性将此时管道内数据读取完并清空管道。
当父进程关闭管道后,若管道中还有数据时read函数会一次性读取完并在下一次读取时返回0,没有数据时直接返回0。
1 #include<iostream>
2 #include<cstdio>
3 #include<unistd.h>
4 #include<string>
5 #include<assert.h>
6 using namespace std;
7 int main()
8 {
9 int pfd[2] = { 0 };
10 int ret = pipe(pfd);
11 assert(ret == 0);
12 printf("main:%d\n",getpid());
13 pid_t id = fork();
14 assert(id >= 0);
15 if (id < 0)
16 {
17 printf("Failed to fork\n");
18 return -1;
19 }
20 else if(id == 0)
21 {
22 close(pfd[1]);
23 //关闭写端
24 char GetStr[1024] = { 0 };
25 ssize_t i = read(pfd[0], GetStr, sizeof GetStr);//接收数据
26 GetStr[i] = '\0';
27 cout << GetStr << endl;
28 printf("son:%d\n",getpid());
29 //cout << getpid()<< endl;
30 exit(0);
31 }
32 else
33 {
34 printf("parent:%d\n",getpid());
35
36 }
37 //父进程
38 printf("main second:%d\n",getpid());
39 close(pfd[0]);
40 char str[1024] = "hello world";
41 write(pfd[1], str, sizeof str);//发送数据
42
43 return 0;
44 }
输出结果如下:
四、命名管道
1.什么是命名管道?
匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件。
2.怎么创建命名管道(函数)?
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:
mkfifo filename
命名管道也可以从程序里创建,相关函数有 :
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename,mode_t mode);
filename:命名管道的名字
mode:权限值
返回值:成功返回0,失败返回-1
3.命名管道的打开规则
如果当前打开操作是为读而打开FIFO时:
- O_NONBLOCK (disable):阻塞直到有相应进程为写而打开该FIFO
- O_NONBLOCK (enable):立刻返回成功
如果当前打开操作是为写而打开FIFO时 :
- O_NONBLOCK (disable):阻塞直到有相应进程为读而打开该FIFO
- O_NONBLOCK (enable):立刻返回失败,错误码为ENXIO
4.怎么使用命名管道?命名管道有什么用?(例子)
processA.cc
1 #include "fifo.h"
2 using namespace std;
3 bool MakeFifo()
4 {
5 int n = mkfifo(FIFONAME, 0644);
6 if(n < 0)
7 {
8 cout << "mkfifo fail" << endl;
9 return false;
10 }
11 return true;
12 }
13
14 int main()
15 {
16 //创建命名管道
17 if(!MakeFifo())
18 {
19 cerr << "mkfifo fail" << endl;
20 return 1;
21 }
22 //打开fifo文件写
23 int wfd = open(FIFONAME, O_WRONLY);
24 if(wfd < 0)
25 {
26 cerr << "open fifo fail" << endl;
27 return 2;
28 }
29 cout << "Process A is sending a message to process B" << endl;
30 char message[] = "i am process A";
31 write(wfd, message, sizeof(message));
32
33 return 0;
34 }
1 #include "fifo.h"
2 using namespace std;
3
4 int main()
5 {
6 //打开fifo文件写
7 int rfd = open(FIFONAME, O_RDONLY);
8 if(rfd < 0)
9 {
10 cerr << "open fifo fail" << endl;
11 return 2;
12 }
13 cout << "receives messages from process A: ";
14 char message[30];
15 read(rfd, message, sizeof(message));
16
17 cout << message << endl;
18
19 return 0;
20 }
fifo.h
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <iostream>
4 #include <cassert>
5 #include <fcntl.h>
6 #include <unistd.h>
7
8 #define FIFONAME "fifo"
五、匿名管道和命名管道的区别
- 匿名管道由pipe函数创建并打开。
- 命名管道由mkfifo函数创建,打开用open
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义