我有以下程序:
int main(int argc, char **argv)
{
char *program;
char stringa[1000] = "";
int num = 0;
char snum[10];
int pipefd[2];
pipe(pipefd);
program = argv[1];
sprintf(stringa, "./%s", program);
pid_t pid = fork();
if (pid < 0 ) {
perror("fork failed.");
exit(1);
}
else if (pid == 0) {
char* args[] = {stringa, NULL};
execv(args[0], args);
}
else {
char procmon_str[] = "./procmon";
num = pid;
sprintf(snum, "%d",num);
pid_t pid2 = fork();
if (pid2 == 0) { //launch procmon
char* args2[] = {procmon_str, snum, NULL};
close(pipefd[0]); //close reading end in the child
dup2(pipefd[1], 1); //send stdout to the pipe
dup2(pipefd[1], 2); //send stderr to the pipe
close(pipefd[1]); //this descriptor is no longer needed
execv(args2[0], args2);
}
else {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
char* args3[] = {"./filter", NULL};
execv(args3[0], args3);
}
}
return 0;
}
我是这样推出的:
./myProgram process
然后,发生以下情况:
myProgram
启动process
并确定其PID
procmon
PID
程序
filter
procmon
的输出应发送到filter
的输入,意思是 - filter
将从其标准输入中读取procmon
写入其标准输出的内容。
出于某种原因,我没有得到预期的结果。
procmon
的工作是获取给定进程的PID,访问相应的/proc/PID/stat
文件并打印进程状态。
filter
需要接受它,并且只打印状态从一个变为另一个的行。目前,我没有从filter
得到任何东西。
process
进入循环(10次迭代),休眠3秒,然后启动另一个循环,使变量增加400,000次。
我做得对吗?
答案 0 :(得分:3)
&#34;没有得到预期的结果&#34;不能很好地描述你所面临的问题。
总的来说,代码还不错。我做了一些重大更改和一些无关紧要的更改(移动变量声明,初始化变量而不是分配它们,格式化)。重大变化包括:
execv()
失败时退出。procmon
进程的标准错误重定向到管道。管道创建可能很重要。如最初编写的那样,process
管道的两端都打开了,因此filter
在process
继续时不会在管道上获得EOF。由于process
不太可能使用管道(它没有正式知道哪些文件描述符对它们开放),所以确实没有意义,可能会对管道保持打开造成一定的伤害。
不将标准错误重定向到管道允许我在我使用的测试脚本中看到没有shebang的错误消息。
我使用了stderr.h
和stderr.c
中的一组函数,这些函数可以在https://github.com/jleffler/soq/tree/master/src/libsoq的GitHub上找到。它们简化了错误报告,因此我的大多数程序都使用它们。
这导致了以下代码,它与您所拥有的代码类似:
#include "stderr.h"
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
if (argc != 2)
err_usage("program");
pid_t pid = fork();
if (pid < 0)
err_syserr("failed to fork");
else if (pid == 0)
{
char stringa[1000] = "";
char *program = argv[1];
sprintf(stringa, "./%s", program);
char *args[] = {stringa, NULL};
execv(args[0], args);
err_syserr("failed to execute '%s': ", args[0]);
}
else
{
int pipefd[2];
pipe(pipefd);
pid_t pid2 = fork();
if (pid2 < 0)
err_syserr("failed to fork");
else if (pid2 == 0) // launch procmon
{
int num = pid;
char snum[10];
sprintf(snum, "%d", num);
char procmon_str[] = "./procmon";
char *args2[] = {procmon_str, snum, NULL};
close(pipefd[0]); // close reading end in the child
dup2(pipefd[1], 1); // send stdout to the pipe
//dup2(pipefd[1], 2); // send stderr to the pipe
close(pipefd[1]); // this descriptor is no longer needed
execv(args2[0], args2);
err_syserr("failed to execute '%s': ", args2[0]);
}
else
{
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
close(pipefd[0]);
char *args3[] = {"./filter", NULL};
execv(args3[0], args3);
err_syserr("failed to execute '%s': ", args3[0]);
}
}
/*NOTREACHED*/
return 0;
}
然后我遇到了测试这个问题。我创建了三个shell脚本 - process
,procmon
和filter
。似乎process
做什么并不重要,只要它需要一些时间来做。 procmon
可能是为了监控流程的状态;它不能成为标准程序,因为您在当前目录中运行它。同样,filter
可能意味着修改它从输入中读取的内容。所以,我发明了脚本来完成这些工作:
<强>过程强>
#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $$" -r 0.2 -s 0.5 -t
<强>将procmon 强>
#!/bin/sh
exec timeout -t 2m -- dribbler -m "$0: PID $1" -r 0.3 -t
过滤强>
#!/bin/sh
echo "$0 at work"
exec grep -e '^[0-9]*9[0-9]*:' -- -
dribbler
程序是一个家庭酿造,慢慢地写信息,和timeout
程序(也是家庭酿造,版本回到1989年,而不是同名的GNU程序)在指定时间后停止其过程。 -r
的{{1}}和-s
选项实现了高斯时间分布(dribbler
平均睡眠时间,默认为1秒,-s
标准差为随机性)。 -r
脚本宣布它正忙,然后在输出的第一个字段中查找9。
有了这个基础设施,我的输出就像:
filter
$ pp37 process
./filter at work
0: ./process: PID 48812
1: ./process: PID 48812
2: ./process: PID 48812
…
9: ./process: PID 48812
10: ./process: PID 48812
…
20: ./process: PID 48812
21: ./process: PID 48812
9: ./procmon: PID 48812
22: ./process: PID 48812
23: ./process: PID 48812
…
92: ./process: PID 48812
93: ./process: PID 48812
49: ./procmon: PID 48812
94: ./process: PID 48812
95: ./process: PID 48812
96: ./process: PID 48812
97: ./process: PID 48812
98: ./process: PID 48812
99: ./process: PID 48812
100: ./process: PID 48812
101: ./process: PID 48812
102: ./process: PID 48812
…
116: ./process: PID 48812
117: ./process: PID 48812
59: ./procmon: PID 48812
118: ./process: PID 48812
119: ./process: PID 48812
…
140: ./process: PID 48812
69: ./procmon: PID 48812
141: ./process: PID 48812
…
161: ./process: PID 48812
162: ./process: PID 48812
79: ./procmon: PID 48812
163: ./process: PID 48812
…
179: ./process: PID 48812
180: ./process: PID 48812
89: ./procmon: PID 48812
181: ./process: PID 48812
182: ./process: PID 48812
90: ./procmon: PID 48812
183: ./process: PID 48812
91: ./procmon: PID 48812
184: ./process: PID 48812
185: ./process: PID 48812
186: ./process: PID 48812
92: ./procmon: PID 48812
187: ./process: PID 48812
188: ./process: PID 48812
93: ./procmon: PID 48812
189: ./process: PID 48812
94: ./procmon: PID 48812
190: ./process: PID 48812
191: ./process: PID 48812
95: ./procmon: PID 48812
192: ./process: PID 48812
193: ./process: PID 48812
96: ./procmon: PID 48812
194: ./process: PID 48812
195: ./process: PID 48812
196: ./process: PID 48812
97: ./procmon: PID 48812
197: ./process: PID 48812
98: ./procmon: PID 48812
198: ./process: PID 48812
199: ./process: PID 48812
200: ./process: PID 48812
201: ./process: PID 48812
99: ./procmon: PID 48812
202: ./process: PID 48812
…
220: ./process: PID 48812
109: ./procmon: PID 48812
221: ./process: PID 48812
…
234: ./process: PID 48812
235: ./process: PID 48812
$
的输出未被过滤,因此显示了该行的每一行,但过滤了process
的输出,只显示了带有procmon
的行。这似乎表现得很正确。