2014-09-06 97 views
1

我的一個C++程序調用fork()並且子程序立即執行另一個程序。我必須與孩子交互,但同時終止其父母,因爲它的可執行文件將被替換。我以某種方式需要將孤兒帶回前臺,以便我可以通過bash與它進行交互 - 目前我只能得到它的輸出。因此,我需要將父級發送到後臺,將子級發送到前臺,然後終止父級,或者在父級終止時立即將子級發送到後臺。發送後臺進程到前臺

據我所知,我必須在其父母終止之前將孩子設置爲過程組長。 從this thread慷慨借款,我得出了以下的試驗場(注意,這是不完整的程序 - 它只是列出了補償過程):

int main(int argc, char *argcv[]) 

printf("%i\n", argc); 
printf("\nhello, I am %i\n", getpid()); 
printf("parent is %i\n", getppid()); 
printf("process leader is %i\n", getsid(getpid())); 
int pgrp; 
std::stringstream pidstream; 
pidstream << tcgetpgrp(STDIN_FILENO); 
pidstream >> pgrp; 
printf("foreground process group ID %i\n", pgrp); 

if(argc==1) 
{ 
    int child = fork(); 
    if(!child) {execl("./nameofthisprogram","nameofthisprogram", "foo", NULL);} 
    else 
    { 
     signal(SIGTTOU, SIG_IGN); 
     usleep(1000*1000*1); 
     tcsetpgrp(0, child); 
     tcsetpgrp(1, child); 

     std::stringstream pidstream2; 
     pidstream2 << tcgetpgrp(STDIN_FILENO); 
     pidstream2 >> pgrp; 
     printf("foreground process group ID %i\n", pgrp); 
     usleep(1000*1000*3); 
     return 0;   
    } 
} 
// signal(SIGTTOU, SIG_IGN); unnecessary 

int input; 
int input2; 

printf("write something\n"); 
std::cin >> input; 
printf("%i\n", input); 
usleep(1000*1000*3); 
printf("%i\n", input); 

printf("write something else\n"); 
std::cin >> input2; 
usleep(1000*1000*3); 
printf("%i\n", input2); 

return 0; 

與上面的代碼中,父母去世我得到提示後,爲第一個輸入。如果我在超出父母死亡的時候推遲了我的答案,它會拾取第一個輸入字符並再次打印。對於input2,程序不會等待我的輸入。 因此,似乎在第一個字符後,輸入被完全終止。 我接近這個根本錯誤,還是僅僅是重新分配幾個ID並改變一些信號?

+1

前景?背景?你什麼意思? – texasbruce 2014-09-06 03:18:36

+2

爲什麼你需要'fork'?看起來你只有一個流程實際上在做任何事情;你可以直接'execl'而不分叉。 。 。 – ruakh 2014-09-06 03:27:17

+0

@ruakh這個程序只是真實程序中的一個子進程的大綱 - 子進程最終會刪除父進程的可執行程序。 – Kartoffelpelz 2014-09-06 10:19:30

回答

0

我在這裏看到一些錯誤。

  1. 你永遠不會把子進程放在它自己的進程組中;因此,它仍保留在原來的一箇中,因此在前景中連同其父
  2. 您打給tcsetpgrp()兩次;它只需要被調用一次。假設沒有重定向,stdin和stdout都指向終端,因此任何一個調用都可以。

通過上面的代碼,在獲得第一個輸入提示後,父項將死亡。如果我在超出父母死亡的時候推遲了我的答案,它會拾取第一個輸入字符並再次打印。對於input2,程序不會等待我的輸入。所以看起來,在第一個字符後,輸入完全終止。

什麼您看到的是這裏是1.的直接後果:因爲兩個進程都在前臺,他們都爭着從標準輸入讀取和結果是不確定的。

我以某種方式需要得到孤兒回到前臺,以便我可以通過bash與它交互 - 我目前只獲得它的輸出。

從我所瞭解的情況來看,你會期望與fork()/exec()之後的exec'ed孩子進行互動。要做到這一點,孩子需要在自己的過程組中,需要放在前臺。

int child = fork(); 
signal(SIGTTOU, SIG_IGN); 
if (!child) { 
    setpgid(0, 0); // Put in its own process group 
    tcsetpgrp(0, getpgrp()); // Avoid race condition where exec'd program would still be in the background and would try to read from the terminal 
    execl("./nameofthisprogram","nameofthisprogram", "foo", NULL); 
} else { 
    setpgid(child, child); // Either setpgid call will succeed, depending on how the processes are scheduled. 
    tcsetpgrp(0, child); // Move child to foreground 
} 

請注意,我們在父對象和子對象中都調用setpgid()/tcsetpgrp()對。我們這樣做是因爲我們不知道哪一個將被首先安排,並且我們想要避免exec'ed程序試圖從stdin讀取(因此收到一個SIGTTIN會阻止該過程)之前的競爭條件已經有時間把它放在前臺。我們也忽略了SIGTTOU,因爲我們知道孩子或父母會收到一個電話號碼爲tcsetpgrp()