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

时间:2013-12-27 03:47:19

标签: c linux fork pipe kill

为了解决我的问题,我订了 在我prctl(PR_SET_PDEATHSIG, SIGHUP);之前调用exec* #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; } } ,并取出我们管道PID的部分。有用!!!!!哇....

但是,stackoverflow不会让我说我已经回答了我自己的问题......

所以我试着编写一个程序,我想运行一个程序,并在cpl秒后杀死该程序,如果它没有完成。 DADDY分离了一个CHILD,它将另一个BABY分开,孩子将BABY的PID输送到DADDY,然后等待一秒钟,如果他们还没有结束他们的业务就杀死他们(这是一个令人毛骨悚然的场景)。但它不起作用,DADDY保持在S +状态,而Baby的无限循环一直持续到我ctr + c。从好的方面来说,这段代码是我在堆栈溢出时学到的所有内容的合并。我们走了。

{{1}}

归功于quinsley和vijay!

2 个答案:

答案 0 :(得分:3)

我看代码的各种评论:

  1. 使用换行符结束消息;你现在在Linux上,而不是Windows。 Windows系统似乎鼓励人们在没有换行符的情况下留下消息,但它在Unix上尤其是Linux上无法正常工作。

  2. 如果您希望显示错误消息,请不要使用_exit(),尤其是那些不以换行符结尾的错误消息。

  3. 不要在标准输出上报告错误消息;报告他们标准错误(这就是它的用途!)。

  4. 如果后面有一个else if (argc == 2) { }子句,那么写else(大括号中没有任何内容)有点奇怪,但如果没有else子句则没有意义。您应该可以测试argc != 2,因为这是正确的参数数量(或者更准确地说,argc == 2之外的任何参数都会被忽略)。

  5. 如果您想睡一段涉及亚秒级时间(例如1.3秒)的时间,请使用适当的亚秒级睡眠命令之一。在这种情况下,nanosleep()可能是要使用的功能。

  6. 除紧急情况外,请勿使用SIGKILL。用SIGKILL发出信号的过程没有机会进行清理或其他任何事情;它被立即杀死(当然,假设你的进程可以向另一个发送信号)。

  7. case -1: printf("syserr");之后没有break;意味着在出错时,控制流程会进入以下case 0:代码,而这不是必需的代码。 break;exit(1);可能是合适的。 (Bullet 3也适用。)

  8. 不要关闭标准错误。代码:

    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标准保证了它,但你必须合作并确保你没有关闭标准错误。

  9. 一些演员:

    diff = ((double)((uintmax_t)(clock_t)done) - (double)((uintmax_t)(clock_t)launch)) / (double)CLOCKS_PER_SEC;
    

    是不必要的。由于donelaunch都属于clock_t类型,因此不需要转换为clock_t。对uintmax_t的中间演员也不是必需的。你可以简单地写:

    diff = ((double)done - (double)launch) / (double)CLOCKS_PER_SEC;
    

    即便如此,三个演员阵容中的两个在理论上是多余的(三者中的任何两个都可以被删除)。

  10. read_from_pipe()中的代码很奇怪且容易出错。由于你有一个文件流,只需使用fscanf()从中读取一个整数,而不是使用双算术和小数值的好奇构造,然后在末尾乘以。这是特别合适的,因为write_to_pipe()代码使用printf("%d", ...);来写入数据。由于c已经是int,因此return (int)c;中的广告素材是多余的。

  11. 理论上,检查fdopen()返回的流以确保操作不会失败是个好主意。

  12. 如果pipe()函数失败,则报告标准输出上的错误,然后继续,因为没有出错。

  13. 目前尚不清楚racket命令实际上做了什么。它在我的机器上不存在。

  14. argv中的spawnfp()未使用。

  15. pid = fork(); if (pidDos < (pid_t) 0)会生成警告(准确地说),pidDos可能未经初始化使用。这个条件大概应该使用pid,而不是pidDos。然后,您将SIGKILL信号发送到由pidDos随机识别的PID,这不太可能带来快乐。

  16. 当我将cat复制到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;
        }
    }
    

答案 1 :(得分:0)

我做了一段时间以获得愚蠢的乐趣,它耗尽了大部分cpu来运行,但我确信你可以修改它以在某个时刻打破或者满足你的需求。

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main(int argc, char*argv[])
{
    int childpid;
    int pids[100];
    int count1 = 0, count2 = 0;
    int count3 = 0;

    L1:
    childpid = fork();

    if(childpid == 0)
    {       

    }   
    else
    {

        if(childpid != 0 && childpid != -1)
        {
            if(count3 < 100)
            {
                pids[count3] = childpid;
                printf("Pid:%d\n",pids[count3]);                
                count3++;
                goto L1;
            }
            else
            {
                count3--;
                goto L2;
            }   
        }

        L2:
            while(count3 > 0)
            {
                if(pids[count3] != -1 || pids[count3] != 1)
                {
                    printf("Killing pid:%d\n",pids[count3]);
                    kill(pids[count3],SIGKILL);
                }       
                count3--;
            }

            if(count3 == 0)
            {
                goto L1;
            }   
    }

    return 0;
}