簡體   English   中英

wait命令不會等待子進程完成c cpp c ++

[英]wait command wont wait for child process to finish c cpp c++

我正在嘗試編寫一個c ++程序,該程序創建一個子進程,運行一個命令,並將輸出通過管道傳遞回父級正在運行的命令的輸入。

我讓父母執行wait(NULL)或wait((void *)pid)命令,但它不等待。

這是代碼:

#include <string.h>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
using namespace std;

int main(int argc, char * argv[])
{    
        char* commands[strlen(argv[1])];
        char *command = NULL;
        command = strtok(argv[1],"|");
        int i = 0;
        while(command != NULL)
        {
                commands[i] = command;
                i++;
                command = strtok(NULL,"|");
        }

        int numberOfCommands = i;

        pid_t pid;
        int pfd[2];
        char* prgname = NULL;
        if(pipe(pfd) == -1)
        {
                perror("error on pipe call");
                return(1);
        }

        for(int j = 0;j<numberOfCommands;j++)
        {
                cout<<commands[j]<<endl;
        }

        pid = fork();
        if(pid == 0){//child process
                printf("Child: My PID = %d\n", getpid());
                printf("Child: Running...\n");
                close(pfd[0]); //close read end of pipe
                dup2(pfd[1],1);//connect the pipes
                close(pfd[1]);//close extra file descriptors
                prgname = commands[0];//first command
                cout<<"child starting command: "<<prgname<<endl;
                execlp(prgname, prgname, 0);//Load the program
                **printf("Child: Done sleeping, returning.\n");**
        }
        else
        {
                printf("Parent: My PID = %d\n", getpid());
                **wait((void*)pid); //also tried wait(NULL); same effect
                printf("Parent: Running...\n");**
                close(pfd[1]); //close the write end of the pipe
                dup2(pfd[0],0);//connect the pipes
                close(pfd[0]); //close extra file descriptor
                prgname = commands[1];//now run the second command
                cout<<"parent starting command: "<<prgname<<endl;
                execlp(prgname, prgname, 0);//Load the programm
        }
        cout<<"all done"<<endl;
        return 0;
}

不要采用粗體字。 我希望父進程等待wait()命令,然后子進程將打印出“子進程正在休眠...”,然后完成操作,然后父進程將打印出“父進程:正在運行...”。

我究竟做錯了什么!

謝謝!

更新:程序的完整輸出為:

dmegs
more
Child: My PID = 30070
Child: Running...
Parent: My PID = 30066
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done

我看到四個問題:

1) execlp()失敗:如果成功, execlp() (或任何exec系列功能)將完全替換當前正在運行的進程映像-除非出現問題,否則它不會返回。 但是您看到的是“孩子:睡着了,回去了”的消息,所以它不可能成功。 (在您的示例中,我想這可能是因為dmegs應該是dmesg 。)

2) printf()cout輸出緩沖意味着無法保證您按發生的順序獲得輸出。 如果要通過打印輸出進行調試,最好打印到(默認情況下)沒有緩沖的stderr (例如,使用fprintf(stderr, ...) )。

3)如其他人所述, wait((void *)pid)是錯誤的。 wait(NULL)waitpid(pid, NULL, 0)

4)這個問題是否與平台相關,但是... execlp()的終止空指針參數應顯式寫為(char *)0而不是0 ,以確保將其傳遞為指針而不是整數。 通常,在C語言中,指針上下文中的0根據定義是一個空指針,但是當將參數傳遞給具有可變數量參數的函數時,編譯器沒有足夠的信息來知道您正在嘗試在指針上下文中使用它,因此,除非您明確將其強制轉換,否則它將作為整數傳遞。 在指針和整數大小不同的平台上,這可能會給您帶來麻煩。


因此我認為wait()正在工作,子進程實際上並未運行您想要的命令,並且由於緩沖,父子進程的輸出變得混亂。


這是代碼的略微修改版本,它不使用任何C ++,切掉命令處理內容,而只是將sleep 5的輸出通過管道傳遞給cat (這毫無意義,因為sleep不會生成任何輸出,但延遲對於了解發生的情況很有用):

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void)
{    
        pid_t pid;
        int pfd[2];
        if(pipe(pfd) == -1)
        {
                perror("error on pipe call");
                return(1);
        }

        pid = fork();
        if(pid == 0){//child process
                fprintf(stderr, "Child: My PID = %d\n", getpid());
                fprintf(stderr, "Child: Running...\n");
                close(pfd[0]); //close read end of pipe
                dup2(pfd[1],1);//connect the pipes
                close(pfd[1]);//close extra file descriptors
                fprintf(stderr, "child starting command: sleep 5\n");
                execlp("sleep", "sleep", "5", (char *)0);//Load the program
                fprintf(stderr, "child: execlp failed\n");
        }
        else
        {
                fprintf(stderr,"Parent: My PID = %d\n", getpid());
                wait(NULL);
                fprintf(stderr,"Parent: Running...\n");
                close(pfd[1]); //close the write end of the pipe
                dup2(pfd[0],0);//connect the pipes
                close(pfd[0]); //close extra file descriptor
                fprintf(stderr,"parent starting command: cat\n");
                execlp("cat", "cat", (char *)0);//Load the programm
        }
        fprintf(stderr,"all done\n");
        return 0;
}

輸出:

$ gcc -Wall -o wait wait.c
$ ./wait
Child: My PID = 27846
Child: Running...
child starting command: sleep 5
Parent: My PID = 27845

(這里有5秒的延遲)

Parent: Running...
parent starting command: cat
$

您通常會打開結果以考慮錯誤情況

pid = fork();
switch( pid ) {
 case -1: // parent fail
 case 0: // child success
 default: // parent success
}

等待您想要使用的特定孩子

waitpid( pid, NULL, 0 );

或等待任何孩子

pid_t child = waitpid( -1, NULL, 0 );

你為什么這么做

wait((void*)pid)

等待將指針指向狀態

   #include <sys/types.h>
   #include <sys/wait.h>

   pid_t wait(int *status);

您幾乎肯定會傳遞不可寫的地址。 測試等待重新編碼,我打賭正在抱怨很多時間;

另外,混合使用printf和cout是一種使自己困惑的方法,它們的緩沖/刷新方案可能不同

wait((void*)pid);

您不應該為了使編譯器停止抱怨而將內容強制轉換為void *。 :)

看來您可能想要waitpidhttp : //linux.die.net/man/2/waitpid

更新:

您需要檢查execlp調用是否真正起作用。 相比:

$ ./a.out "dmegs|more"
dmegs
more
Parent: My PID = 20806
Child: My PID = 20807
Child: Running...
Parent: Running...
parent starting command: more
child starting command: dmegs
Child: Done sleeping, returning.
all done

有:

$ ./a.out "dmesg|more"
dmesg
more
Parent: My PID = 20876
Child: My PID = 20877
Child: Running...
^C

在第一種情況下,由於execlp找不到“ dmegs”,因此子進程基本上會立即退出。 這將解除對父進程的阻止,並允許其執行。

暫無
暫無

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

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