簡體   English   中英

在子進程終止之前從父程序退出()程序

[英]exit() the program from parent before child process has terminated

我有一個C服務器。 該服務器必須處理多個連接用戶輸入(通過簡單的ncurses GUI)。 所以我創造了兩個孩子。
我的問題來自用戶界面的主菜單,我需要exit程序(然后終止第一個子進程的第二個子進程( 處理連接 ))。

我將用一個小例子來解釋一下自己:

int main(){
    pid_t pid;
    int status1, status2;
    if((pid = fork()) < 0){
        perror("main fork failure:");
        exit(1);
    }

    if(pid == 0){
        pid = fork();
        if(pid == 0){
            /*  
                some stuff the second child does while 
                the first child is already running
            */
        }
        /* this is the first child */
        int choice;
        choice = menu();
        switch(choice){
            case 1:
                break;
            case 2:
                /* 
                   HERE I have to exit (from the first child first,
                   and from the program then): how can I kill the
                   second child that is running to prevent
                   zombie processes? 
                */
                // kill() which pid?
                exit(2);
                break;
        }
        wait(&status2);
    }
    wait(&status1);
    return 0;
}

因此,如果我不知道第一個孩子的第二個孩子pid ,該如何kill它?

在您的代碼中,您重用了變量pid ,但是幸運的是,非零pid是您需要發信號的那個。

因此:

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

extern int menu(void);

static void wait_for_pid(int pid)
{
    int status;
    int corpse;
    while ((corpse = wait(&status)) >= 0 && corpse != pid)
        printf("Unexpected child %d exited with status 0x%.4X\n", corpse, status);
    if (corpse == pid)
        printf("Child %d exited with status 0x%.4X\n", corpse, status);
    else
        printf("Child %d died without its death being tracked\n", pid);
}

int main(void)
{
    pid_t pid;
    if ((pid = fork()) < 0)
    {
        perror("main fork failure:");
        exit(1);
    }

    if (pid == 0)
    {
        if ((pid = fork()) < 0)
        {
            perror("child fork failure:");
            exit(1);
        }
        if (pid == 0)
        {
            pause();    /* Do nothing until signalled */
            exit(0);
        }
        /* this is the first child */
        int choice = menu();
        switch (choice)
        {
        case 1:
            /* action 1 */
            break;
        case 2:
            kill(pid, SIGTERM);
            exit(2);
            /*NOTREACHED*/
        }
        wait_for_pid(pid);
        exit(0);
    }
    wait_for_pid(pid);
    return 0;
}

對於孩子來說, wait_for_pid()函數中的循環應該是多余的,但是在某些情況下(可能但並非並非不可能),父進程可能會有它不知道的子進程。

在第二個孩子中使用pause()只是在編寫一些代碼。 它沒有用,因此不會是您在此處寫的內容。 編寫注釋/* action 1 */同樣是偽代碼; 您將用功能有用的代碼替換它。 我可能有調用第一個孩子和第二個孩子的函數,而不是在main()嵌入很多代碼。 我假設它的編寫如圖所示,以創建MCVE( 最小,完整,可驗證的示例 ); 感謝您使代碼保持較小。


上面的代碼未經測試,因為沒有menu()函數。 下面的代碼具有菜單功能-並不是很互動。

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

extern int menu(void);

int menu(void)
{
    printf("Dozing...\n");
    sleep(1);
    printf("Menu option 2 chosen\n");
    return 2;
}

static void wait_for_pid(int pid)
{
    int status;
    int corpse;
    int curpid = getpid();
    printf("%d: waiting for children to die\n", curpid);
    while ((corpse = wait(&status)) >= 0 && corpse != pid)
        printf("%d: Unexpected child %d exited with status 0x%.4X\n", curpid, corpse, status);
    if (corpse == pid)
        printf("%d: Child %d exited with status 0x%.4X\n", curpid, corpse, status);
    else
        printf("%d: Child %d died without its death being tracked\n", curpid, pid);
}

int main(void)
{
    pid_t pid;
    if ((pid = fork()) < 0)
    {
        perror("main fork failure:");
        exit(1);
    }

    if (pid == 0)
    {
        if ((pid = fork()) < 0)
        {
            perror("child fork failure:");
            exit(1);
        }
        if (pid == 0)
        {
            printf("Second child (%d) - pausing\n", (int)getpid());
            pause();    /* Do nothing until signalled */
            printf("Second child (%d) - awake despite no signal handling\n", (int)getpid());
            exit(0);
        }
        /* this is the first child */
        printf("First child (%d) - menuing\n", (int)getpid());
        int choice = menu();
        switch (choice)
        {
        case 1:
            /* action 1 */
            break;
        case 2:
            printf("kill(%d, SIGTERM)\n", pid);
            kill(pid, SIGTERM);
            wait_for_pid(pid);
            exit(2);
            /*NOTREACHED*/
        }
        /* Reached on menu choices != 2 */
        /* Probably needs a loop around the menu() - end loop before wait_for_pid()  */
        wait_for_pid(pid);
        exit(0);
    }
    wait_for_pid(pid);
    return 0;
}

運行時,示例輸出序列為:

19489: waiting for children to die
First child (19490) - menuing
Dozing...
Second child (19491) - pausing
Menu option 2 chosen
kill(19491, SIGTERM)
19490: waiting for children to die
19490: Child 19491 exited with status 0x000F
19489: Child 19490 exited with status 0x0200

所有這些看起來都可以預期。 您可以在狀態0x000F中看到SIGTERM的死亡(SIGTERM通常為15,而在macOS Sierra上為15,盡管AFAIK沒有標准要求它為15)。 您可以看到第一個孩子從0x0200正常退出,狀態為2。 您會看到,父母開始等待孩子做任何事情。 您會看到調試技術-大量時間打印並包括PID。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM