gpt4 book ai didi

c - 父进程在无限循环中杀死子进程

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:55:12 24 4
gpt4 key购买 nike

为了解决我的问题,我设置了
prctl(PR_SET_PDEATHSIG, SIGHUP);如在我调用exec*之前的stackoverflow answer中所示,并取出管道pid的部分。它起作用了!!!!!真的。。。。
不过,斯塔克弗洛夫不会让我说我已经回答了我自己的问题…
所以我试着写一个程序,我想运行一个程序,如果它没有完成,在cpl秒后杀死它。爸爸把一个孩子劈开,孩子把另一个孩子劈开,孩子把孩子的PID管道给爸爸,然后爸爸再等一秒钟,如果他们还没有结束他们的生意,他们两个都会死(这是一个可怕的场景)。但它不起作用,爸爸保持在s+状态,无限循环即baby一直持续到i ctr+c。好的一面是,这段代码是我在stack overflow中学到的所有东西的组合。给你。

#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;
}
}

归功于昆斯利和维杰!

最佳答案

我看到代码时的各种注释:
以换行符结束消息;您现在使用的是Linux,而不是Windows。Windows系统似乎鼓励人们在没有换行符的情况下留言,但它在一般的Unix,特别是Linux上不会很好地工作。
如果希望显示错误消息,尤其是不以换行结尾的错误消息,请不要使用_exit()
不要在标准输出上报告错误消息;在标准错误上报告它们(这就是它的用途!)是的。
如果后面有一个else if (argc == 2) { }子句,则写else(括号中没有任何内容)有点奇怪,但如果没有else子句,则写argc != 2是没有意义的。您应该对argc == 2进行测试,因为这是正确数量的参数(或者更准确地说,忽略nanosleep()以外的任何参数)。
如果您希望睡眠的时间包括亚秒计时(例如1.3秒),请使用适当的亚秒睡眠命令之一。在这种情况下,case -1: printf("syserr");可能是要使用的函数。
除非在紧急情况下,不要使用sigkill。用sigkill发出信号的进程没有机会清理或执行任何操作;它会立即被终止(当然,假设允许您的进程向另一个进程发送信号)。
break;case 0:表示出错后,控制流进入以下break;代码,这不是必需的。exit(1);done可能是合适的。(项目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;

没有必要。由于 launchclock_t都是 clock_t类型,因此不需要对 uintmax_t进行强制转换。中间转换到 read_from_pipe()也不是真正必要的。你可以简单地写下:
diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;

即使这样,三个类型中的两个在理论上也是多余的(三个类型中的任何两个都可以删除)。
fscanf()中的代码既奇怪又容易出错。既然已经有了一个文件流,那么只需使用 write_to_pipe()从中读取一个整数,而不是使用双算术和小数的奇怪构造,然后在末尾乘以它们。这特别合适,因为 printf("%d", ...);代码使用 c来编写数据。因为 int已经是 return (int)c;,所以cast-in fdopen()是多余的。
理论上,最好检查 pipe()返回的流,以确保操作不会失败。
如果 racket函数失败,则在标准输出上报告错误,然后继续,因为没有出现任何错误。
目前尚不清楚 argv命令的实际作用。它不存在于我的机器上。
spawnfp()中的 pid = fork(); if (pidDos < (pid_t) 0)未使用。
pidDos会(准确地)生成一个警告, pid可能在未初始化的情况下使用。这种情况应该使用 pidDos,而不是 pidDos。然后,向由 cat随机识别的pid发送sigkill信号,这不太可能导致幸福。
当我将 racket复制到 mk并调用以下代码(作为从 mk.c构建的程序)作为 mk /etc/passwd时,我会看到密码文件的双倍行距(以及来自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(),在那里创建的子项需要在执行“racket”之前关闭管道描述符。这是由 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;
}
}

关于c - 父进程在无限循环中杀死子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20794426/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com