在进程中的同一管道上进行读写时 C++ 管道出现问题
Problem with C++ pipes when doing a read and write on the same pipe in a process
我正在学习管道和叉子。我试图通过使用管道和叉子来表示 ps -A | grep kworker | wc -l
来获取 kworker 进程的数量。在我为 grep 语句执行管道之前,我的代码一直在正常工作。
我运行我的代码是这样的:./a.out kworker
#include <iostream>
#include <unistd.h> // for fork()
#include <sys/wait.h> // for wait()
using std::cout;
using std::endl;
int main(int num = 1, char * args[] = NULL)
{
int pipefd[2];
pipe(pipefd);
char * p[3];
/*
wait for grandchild to complete ps - A
wait for child to complete grep kworker
execute wc -l
*/
p[2] = NULL;
pid_t id1 = fork(); // get child process
if(id1 == -1)
{
perror("fork");
close(pipefd[0]);
close(pipefd[1]);
}
else if(id1 == 0) // child process
{
pid_t id2 = fork(); // get grandchild process
if(id2 == 0) // grandchild process
{
p[0] = "ps";
p[1] = "-A";
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]); // close read
close(pipefd[1]);
execvp(p[0], p);
perror("exec");
exit(1);
}
else if(id2 > 0) // child process
{
// The problem is in this if-statement
close(pipefd[1]);
wait(0);
p[0] = "grep";
p[1] = args[1];
// I get output from the STDOUT
dup2(pipefd[0], STDIN_FILENO); // read from pipe
dup2(pipefd[1], STDOUT_FILENO); // write to pipe
close(pipefd[1]);
execvp(p[0], p);
}
}
else if(id1 > 0) // parent process
{
// close pipes first
close(pipefd[1]); // close unused write end
wait(0);
p[0] = "wc";
p[1] = "-l";
dup2(pipefd[0], STDIN_FILENO); // read from pipe
close(pipefd[1]);
close(pipefd[0]);
if(execvp(p[0], p) == -1)
{
perror("exec");
exit(1);
}
}
}
代码给我的输出:
6 ? 00:00:00 kworker/0:0H-events_highpri
20 ? 00:00:00 kworker/1:0H-kblockd
26 ? 00:00:00 kworker/2:0H-kblockd
32 ? 00:00:00 kworker/3:0H-kblockd
50 ? 00:00:00 kworker/1:1-events
172 ? 00:00:00 kworker/u17:0-rb_allocator
289 ? 00:00:00 kworker/3:1H
290 ? 00:00:00 kworker/1:1H-events_highpri
296 ? 00:00:00 kworker/0:1H-kblockd
360 ? 00:00:00 kworker/2:1H-events_highpri
550 ? 00:00:00 kworker/u17:1-rb_allocator
1340 ? 00:00:01 kworker/2:4-events
1374 ? 00:00:00 kworker/0:0-events
2751 ? 00:00:00 kworker/3:2-events
2782 ? 00:00:00 kworker/1:2-mm_percpu_wq
5389 ? 00:00:00 kworker/0:1-events
6539 ? 00:00:00 kworker/u16:3-events_unbound
6599 ? 00:00:00 kworker/3:1
6618 ? 00:00:00 kworker/2:1-events
6705 ? 00:00:00 kworker/u16:0-events_unbound
6815 ? 00:00:00 kworker/u16:1-events_unbound
7283 ? 00:00:00 kworker/u16:2-events_unbound
0
我希望输出与以下内容相同:
ps -A | grep kworker | wc -l
21
是什么导致了这个问题?我在这里查看了其他问题,但找不到解决方案。
添加第二个管道解决了问题。我们不能同时读取和写入同一个管道。
看:
close(pipefd[1]);
dup2(pipefd[1], STDOUT_FILENO);
您关闭其中一个 FD。然后将 dup2 与它一起使用。由于 FD 已关闭,dup2 returns 一个错误代码并且不执行任何操作。所以grep的stdout还是正常的stdout。
您的代码还有其他问题。这就是你问的那个。
关于“其他问题”的详细说明:您的代码尝试使用同一个管道两次。 ps
和 grep
从管道读取,grep
和 wc
从管道读取。这意味着数据可以从 ps
直接转到 wc
,或者从 grep
返回到它本身,这不是您想要的。您应该使用两个单独的管道 - 一个将 ps
连接到 grep
,一个将 grep
连接到 wc
.
我正在学习管道和叉子。我试图通过使用管道和叉子来表示 ps -A | grep kworker | wc -l
来获取 kworker 进程的数量。在我为 grep 语句执行管道之前,我的代码一直在正常工作。
我运行我的代码是这样的:./a.out kworker
#include <iostream>
#include <unistd.h> // for fork()
#include <sys/wait.h> // for wait()
using std::cout;
using std::endl;
int main(int num = 1, char * args[] = NULL)
{
int pipefd[2];
pipe(pipefd);
char * p[3];
/*
wait for grandchild to complete ps - A
wait for child to complete grep kworker
execute wc -l
*/
p[2] = NULL;
pid_t id1 = fork(); // get child process
if(id1 == -1)
{
perror("fork");
close(pipefd[0]);
close(pipefd[1]);
}
else if(id1 == 0) // child process
{
pid_t id2 = fork(); // get grandchild process
if(id2 == 0) // grandchild process
{
p[0] = "ps";
p[1] = "-A";
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[0]); // close read
close(pipefd[1]);
execvp(p[0], p);
perror("exec");
exit(1);
}
else if(id2 > 0) // child process
{
// The problem is in this if-statement
close(pipefd[1]);
wait(0);
p[0] = "grep";
p[1] = args[1];
// I get output from the STDOUT
dup2(pipefd[0], STDIN_FILENO); // read from pipe
dup2(pipefd[1], STDOUT_FILENO); // write to pipe
close(pipefd[1]);
execvp(p[0], p);
}
}
else if(id1 > 0) // parent process
{
// close pipes first
close(pipefd[1]); // close unused write end
wait(0);
p[0] = "wc";
p[1] = "-l";
dup2(pipefd[0], STDIN_FILENO); // read from pipe
close(pipefd[1]);
close(pipefd[0]);
if(execvp(p[0], p) == -1)
{
perror("exec");
exit(1);
}
}
}
代码给我的输出:
6 ? 00:00:00 kworker/0:0H-events_highpri
20 ? 00:00:00 kworker/1:0H-kblockd
26 ? 00:00:00 kworker/2:0H-kblockd
32 ? 00:00:00 kworker/3:0H-kblockd
50 ? 00:00:00 kworker/1:1-events
172 ? 00:00:00 kworker/u17:0-rb_allocator
289 ? 00:00:00 kworker/3:1H
290 ? 00:00:00 kworker/1:1H-events_highpri
296 ? 00:00:00 kworker/0:1H-kblockd
360 ? 00:00:00 kworker/2:1H-events_highpri
550 ? 00:00:00 kworker/u17:1-rb_allocator
1340 ? 00:00:01 kworker/2:4-events
1374 ? 00:00:00 kworker/0:0-events
2751 ? 00:00:00 kworker/3:2-events
2782 ? 00:00:00 kworker/1:2-mm_percpu_wq
5389 ? 00:00:00 kworker/0:1-events
6539 ? 00:00:00 kworker/u16:3-events_unbound
6599 ? 00:00:00 kworker/3:1
6618 ? 00:00:00 kworker/2:1-events
6705 ? 00:00:00 kworker/u16:0-events_unbound
6815 ? 00:00:00 kworker/u16:1-events_unbound
7283 ? 00:00:00 kworker/u16:2-events_unbound
0
我希望输出与以下内容相同:
ps -A | grep kworker | wc -l
21
是什么导致了这个问题?我在这里查看了其他问题,但找不到解决方案。
添加第二个管道解决了问题。我们不能同时读取和写入同一个管道。
看:
close(pipefd[1]);
dup2(pipefd[1], STDOUT_FILENO);
您关闭其中一个 FD。然后将 dup2 与它一起使用。由于 FD 已关闭,dup2 returns 一个错误代码并且不执行任何操作。所以grep的stdout还是正常的stdout。
您的代码还有其他问题。这就是你问的那个。
关于“其他问题”的详细说明:您的代码尝试使用同一个管道两次。 ps
和 grep
从管道读取,grep
和 wc
从管道读取。这意味着数据可以从 ps
直接转到 wc
,或者从 grep
返回到它本身,这不是您想要的。您应该使用两个单独的管道 - 一个将 ps
连接到 grep
,一个将 grep
连接到 wc
.