2013-04-29 214 views
3

我必須在C編寫一個程序,將fork一個新進程,然後使用該進程pid作爲另一個函數。不過,我需要在子進程運行之前調用這個函數,我不知道該怎麼做。讓子進程等待父進程

下面是我試圖做的一些僞代碼。

pid_t pid = fork(); 
if(in_child){ //In the child process 
    //launch child application 
    //somehow stop the child application before it actually executes any code 
} 
else{ 
    //call my function with the child's pid 
    //resume the child process 
    //do other stuff 
} 

如果您需要任何其他信息,請詢問。謝謝。

編輯:我沒有訪問孩子的代碼。我只是想運行一個可執行文件。

+0

如何使用管道並讓子進程等待管道中出現的東西? – 2013-04-29 01:26:40

+2

使用信號量。 – Duck 2013-04-29 01:26:51

+0

你打算如何處理父母的孩子的PID?您可以在執行子應用程序之前簡單地讓分叉的孩子等待父母準備好嗎?爲什麼不? – 2013-04-29 04:28:03

回答

2

如果你的意思是任何代碼,那可能很困難。您可以使用cloneCLONE_STOPPED而不是fork來啓動應用程序進入停止狀態(需要SIGCONT才能使其重新開始)。然而,如果你只是指子代碼中的特定代碼,並且你可以修改子代碼,那麼你可以像main中的第一件事情那樣簡單地設置一個USR1信號的處理程序(任何IPC可能只會做一個信號在這種情況下似乎是最簡單的),然後在繼續之前等待它發射。

這樣,過程本身將運行,但不會做任何事情。

然後,您可以讓父母編織它需要做的任何魔法,然後發送一個SIGUSR1給孩子。


但因爲根據註釋,你不訪問客戶端代碼,第一個選項可能是最好的,假設SIGCONT實際上不會引起孩子的問題。這將需要測試。


當然,有一點要記住的是,無論是clone()也不fork()實際上將載入的新程序進入孩子的過程中,必須要後與exec型呼叫完成分裂。這是forkexec功能之間的UNIX拆分的結果,詳細的here

這意味着,當你不控制孩子程序,控件的子過程,因此您的代碼可以等待加載了新的子程序之前,它希望任何信號。因此,即使只有fork()也是可行的。

不幸的是,這也意味着新的程序已經加載後exec(至少不確定性)既不clone也不fork可以停止你的過程是這樣,如果擺弄你想要做的就是將新的程序(如通過附加內存來操縱變量),你不能這樣做。

您可以做的最好的做法是在新程序仍在運行時(在exec之前)拷貝舊程序。

+0

不幸的是,這不會工作,因爲我沒有訪問孩子的代碼,所以我不能把任何東西放在它的主要方法。 – 2013-04-29 01:34:18

+1

@Zac,那麼你應該嘗試'clone'選項。它仍然使用信號,但希望不需要訪問源代碼。通過在前臺運行孩子輕鬆進行測試,使用CTRL-Z將其停止,然後使用「fg」重新啓動它。如果它在沒有投訴的情況下生存下來,它應該使用'clone/CLONE_STOPPED/SIGCONT'。 – paxdiablo 2013-04-29 01:36:53

1

有一種更簡單的方法,假設您的操作系統將允許您在兒童執行官之前共享地址空間。僞代碼如下。

volatile int barrier; 

int safe_fork(routine_to_call) 
{ 
    pid_t pid; 

    barrier = 0; 
    pid = fork(); 
    if (pid == 0) { 
     /* parent */ 
     routine_to_call() 
     barrier = 1; 
    } else if (pid > 0) { 
     while (barrier = 0) 
      ; /* or sleep if it's a slow routine */ 
     exec() 
     //if we get here, exec failed; exit with failure code 
    } else { 
     /* return failure */ 
    } 
    /* must be parent; return success */ 
} 

您可能需要做一些特殊的事情來獲取共享行爲,而不是讓它們都以獨立副本開始。我知道它在FreeBSD上可行。在linux中,查看CLONE_VM標誌爲clone();它看起來應該讓你在這裏做你所需要的。

0

你在找什麼是進程間條件變量。 https://en.wikipedia.org/wiki/Monitor_(synchronization)

它會工作(大約)方式: -

分叉你之前設置一個變量,詢問孩子等着: - child_continue = false

1)子進程開始執行(或父,沒有按「T物質)

  • 如果變量child_continue == false
  • 休眠條件變量和等待信號從父

2.)父進程等待其運行的機會(注意運行順序無關緊要)。當父進程準備好運行時,它可以通過子PID(或其他)執行任何想要的操作,並指示子進程繼續。

爲了做到這一點,你需要進程間互斥和進程間條件變量。

//#include "pthread.h" in main file 

//create IPC MUTEX which can be shared by both child and parent. 

pthread_mutexattr_t mutex_attr; 
pthread_condattr_t cond_attr; 
pthread_mutex_t mtx; 
pthread_cond_t cond; 
if (0!= pthread_mutexattr_init(&mutex_attr)) 
{ 
//errror handling 
} 
if (0!= pthread_condattr_init(&cond_attr)) 
{ 
//errror handling 
} 

if (0 != pthread_condattr_setpshared(&cond_attr,PTHREAD_PROCESS_SHARED) 
{ 
//error handling 
} 
if (0 != pthread_mutexattr_setpshared(&mutex_attr,PTHREAD_PROCESS_SHARED) 
{ 
//error handling 
} 

if (0 !=pthread_mutex_init(&mtx,&mtx_attr)) 
{ 
//error handling 
} 

if (0 !=pthread_cond_init(&cond,&cond_attr)) 
{ 
//error handling 
} 
boolean child_continue = false; 
//now fork !! 

pid_t pi = fork(); 
if (pi ==0) //child 
{ 
    if (0 !=pthread_mutex_lock(&mtx)) 
    { 
    //error handling 
    } 
    while (!child_continue) //wait until we receive signal from parent. 
    { 
    if (0 !=pthread_cond_wait(&cond,&mtx)) 
    { 
    //error handling 
    } 
    } 
    if (0 !=pthread_mutex_unlock(&mtx)) 
    { 
    //error handling 
    } 
    //Parent is done!! either we woke up by condition variable or, parent was done before hand 
    //in which case, child_continue was true already. 
} 
else 
{ 
    //in parent process do whatever you want with child pid (pi variable) 

    //once you are done, set child_continue to true and wake up child. 
    if (0 !=pthread_mutex_lock(&mtx)) 
    { 
    //error handling 
    } 
    child_continue = true; 
    if (0 !=pthread_cond_signal(&cond)) 
    { 
    //error handling 
    } 
    if (0 !=pthread_mutex_unlock(&mtx)) 
    { 
    //error handling 
    } 
}