我看代码的各种cmets:
用换行符结束消息;您现在使用的是 Linux,而不是 Windows。 Windows 系统似乎鼓励人们在留言时不使用换行符,但在一般的 Unix 上,尤其是在 Linux 上,它不能很好地工作。
如果您希望出现错误消息,尤其是不以换行符结尾的错误消息,请不要使用 _exit()。
不要在标准输出上报告错误信息;报告标准错误(这就是它的用途!)。
如果后面有else 子句,那么写else if (argc == 2) { }(大括号中没有任何内容)有点奇怪,但如果没有else 子句,则毫无意义。您应该测试argc != 2,因为这是正确数量的参数(或者更准确地说,任何超出argc == 2 的参数都将被忽略)。
如果您想休眠一段涉及亚秒级计时的时间(例如 1.3 秒),请使用适当的亚秒级休眠命令之一。在这种情况下,nanosleep() 可能是要使用的函数。
除非在紧急情况下,否则不要使用 SIGKILL。用 SIGKILL 发出信号的进程没有机会清理或任何东西;它立即被杀死(当然,假设你的进程被允许向另一个进程发送信号)。
case -1: printf("syserr"); 后面没有break; 表示出错时,控制流进入以下case 0: 代码,这不是必需的。 break; 或 exit(1); 可能是合适的。 (第 3 条也适用。)
-
不要关闭标准错误。代码:
close(1);
close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
_exit(EXIT_FAILURE);
永远不会报告错误;你关闭了标准错误。请记住,程序有权拥有标准错误通道。 C 标准保证它,但你必须配合并确保你没有关闭标准错误。
-
部分演员表:
diff = ((double)((uintmax_t)(clock_t)done) - (double)((uintmax_t)(clock_t)launch)) / (double)CLOCKS_PER_SEC;
是不必要的。因为done 和launch 都属于clock_t 类型,所以不需要转换为clock_t。对uintmax_t 的中间转换也不是必需的。你可以简单地写:
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
即使那样,三个演员中的两个在理论上是多余的(三个中的任何两个都可以删除)。
read_from_pipe() 中的代码很奇怪且容易出错。由于您有一个文件流,因此只需使用fscanf() 从其中读取一个整数,而不是使用双精度算术和小数值然后在最后相乘的奇怪构造。这是特别合适的,因为write_to_pipe() 代码使用printf("%d", ...); 来写入数据。由于c 已经是int,所以return (int)c; 中的演员表是多余的。
理论上,检查fdopen()返回的流以确保操作没有失败是个好主意。
如果 pipe() 函数失败,您会在标准输出上报告错误,然后继续,因为没有出现任何问题。
尚不清楚racket 命令的实际作用。它在我的机器上不存在。
spawnfp() 中的argv 未使用。
pid = fork(); if (pidDos < (pid_t) 0) 生成警告(准确)pidDos 可能未初始化使用。条件大概应该是使用pid,而不是pidDos。然后,您向pidDos 随机标识的 PID 发送一个 SIGKILL 信号,这不太可能带来幸福。
当我将cat 复制到racket 并以mk /etc/passwd 的形式调用以下代码(作为从mk.c 构建的程序mk)时,我会看到双倍行距的密码文件(以及消息来自shell关于Killed: 9。
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
if (fscanf(stream, "%d", &c) != 1)
{
fprintf(stderr, "Failed to read integer from pipe\n");
exit(1);
}
fclose(stream);
return c;
}
static void write_to_pipe(int file, int pidRacket)
{
FILE *stream = fdopen(file, "w");
fprintf(stream, "%d", pidRacket);
fclose(stream);
}
static int spawnpipe(char *fileName, int *fd)
{
int pid;
int pipe_fds[2];
char *command[] = {"racket", fileName, NULL};
if (pipe(pipe_fds) < 0)
{
fprintf(stderr, "FE: pipe\n");
exit(1);
}
switch ((pid = fork()))
{
case -1:
printf("syserr");
exit(1);
case 0:
close(1);
close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
exit(EXIT_FAILURE);
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
static int spawnfp(char *fileName, FILE **fpp)
{
int fd, pid;
pid = spawnpipe(fileName, &fd);
*fpp = fdopen(fd, "r");
return pid;
}
int main(int argc, char *argv[])
{
pid_t pid;
int mypipe[2];
if (pipe(mypipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
pid = fork();
if (pid < (pid_t) 0)
{
fprintf(stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else if (pid != (pid_t) 0)
{
double diff = 0;
clock_t launch = clock();
close(mypipe[1]);
int pidRacket = read_from_pipe(mypipe[0]);
while (diff < 1.3)
{
clock_t done = clock();
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
}
kill(pidRacket, SIGKILL);
kill(pid, SIGKILL);
return EXIT_SUCCESS;
}
else if (pid == (pid_t) 0)
{
close(mypipe[0]);
char buf[100];
FILE *fp;
char *fileName = argv[1];
int pidRacket = spawnfp(fileName, &fp);
write_to_pipe(mypipe[1], pidRacket);
if (argc == 1)
{
printf("Not enough arguments!");
_exit(EXIT_FAILURE);
}
else if (argc == 2)
{
}
sleep(1);
while (fgets(buf, sizeof buf, fp))
{
printf("%s\n", buf);
}
fclose(fp);
kill(pid, SIGKILL);
return 0;
}
}
我修复了此代码修订版中发现的一些问题,但绝不是全部。
哦,第 16 项:管道的读取端直到第三个进程终止才关闭。您需要将mypipe[1] 传递给spawnfp(),这需要将其中继到spawnpipe(),并且在那里创建的子进程需要在执行“球拍”之前关闭管道描述符。 fscanf() 在从管道读取的 PID 末尾寻找 EOF 或非数字,这使情况更加复杂。您可以在最后提供换行符或其他内容,这也将释放父进程以在其计时循环中旋转。既然你说racket 没有终止,这就是为什么你看不到任何东西。
再次粘贴整个程序比显示差异更容易:
#include <assert.h>
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static int read_from_pipe(int file)
{
int c;
FILE *stream = fdopen(file, "r");
assert(stream != 0);
if (fscanf(stream, "%d", &c) != 1)
{
fprintf(stderr, "Failed to read integer from pipe\n");
exit(1);
}
fclose(stream);
return c;
}
static void write_to_pipe(int file, int pidRacket)
{
FILE *stream = fdopen(file, "w");
assert(stream != 0);
fprintf(stderr, "%d: pidRacket = %d\n", (int)getpid(), pidRacket);
fprintf(stream, "%d", pidRacket);
fclose(stream);
}
static int spawnpipe(char *fileName, int *fd, int pfd)
{
int pid;
int pipe_fds[2];
char *command[] = {"racket", fileName, NULL};
if (pipe(pipe_fds) < 0)
{
fprintf(stderr, "FE: pipe\n");
exit(1);
}
switch ((pid = fork()))
{
case -1:
printf("syserr");
exit(1);
case 0:
close(pfd);
close(1);
//close(2);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execvp(*command, command);
perror("execv");
exit(EXIT_FAILURE);
default:
fprintf(stderr, "%d: pid = %d\n", (int)getpid(), pid);
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
static int spawnfp(char *fileName, FILE **fpp, int pfd)
{
int fd, pid;
pid = spawnpipe(fileName, &fd, pfd);
*fpp = fdopen(fd, "r");
assert(*fpp != 0);
return pid;
}
int main(int argc, char *argv[])
{
pid_t pid;
int mypipe[2];
if (pipe(mypipe))
{
fprintf(stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
pid = fork();
if (pid < (pid_t) 0)
{
fprintf(stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else if (pid != (pid_t) 0)
{
double diff = 0.0;
clock_t launch = clock();
close(mypipe[1]);
fprintf(stderr, "%d: Reading from pipe:\n", (int)getpid());
int pidRacket = read_from_pipe(mypipe[0]);
fprintf(stderr, "%d: Read PID %d from pipe\n", (int)getpid(), pidRacket);
while (diff < 1.3)
{
clock_t done = clock();
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
printf("%f\n", diff);
}
kill(pidRacket, SIGKILL);
kill(pid, SIGKILL);
return EXIT_SUCCESS;
}
else if (pid == (pid_t) 0)
{
close(mypipe[0]);
char buf[100];
FILE *fp;
char *fileName = argv[1];
int pidRacket = spawnfp(fileName, &fp, mypipe[1]);
fprintf(stderr, "%d: Writing PID %d to pipe\n", (int)getpid(), pidRacket);
write_to_pipe(mypipe[1], pidRacket);
fprintf(stderr, "%d: Written PID to pipe\n", (int)getpid());
if (argc == 1)
{
printf("Not enough arguments!");
_exit(EXIT_FAILURE);
}
else if (argc == 2)
{
}
sleep(1);
while (fgets(buf, sizeof buf, fp))
{
printf("%s\n", buf);
}
fclose(fp);
fprintf(stderr, "%d: Finished reading from pipe\n", (int)getpid());
kill(pid, SIGKILL);
return 0;
}
}