让子进程等待父进程

时间:2013-04-29 01:22:33

标签: c linux process fork

我必须在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
}

如果您需要任何其他信息,请询问。感谢。

编辑:我无法访问孩子的代码。我只是想运行一个可执行文件。

3 个答案:

答案 0 :(得分:2)

如果您的意思是任何代码,那可能会很困难。您可以将cloneCLONE_STOPPED而不是fork一起使用来启动应用程序进入停止状态(需要SIGCONT再次启动它)。

但是,如果您只是指儿童中的特定代码并且您可以修改子代码,那么您可以main中的第一件事就是为USR1信号设置处理程序(任何IPC可能都会做,但在这个特殊情况下信号似乎最简单)然后等待它继续发射。

这样,进程本身就会运行,但还没有做任何事情。

然后让父母编织它需要做的任何魔法,然后将SIGUSR1发送给孩子。


但是,根据评论,你没有拥有访问客户端代码,第一个选项可能是最好的,假设SIGCONT实际上不会导致问题和孩子在一起这将需要测试。


当然,要记住的一件事是,clone()fork()实际上都不会将新的程序加载到子进程中,而这必须通过分割后调用。这是UNIX在execfork功能之间拆分的结果,详细here

这意味着,虽然您不控制子程序,但您 控制子进程,因此您的代码可以在加载之前等待它想要的任何信号新的儿童计划。因此即使只有exec,它也是可行的。

不幸的是,这也意味着fork()clone都不能在新程序加载fork后(至少没有确定性)加载,因此,如果摆弄你想要做的是新程序(例如通过附加到其内存来操纵其变量),你不能这样做。

你可以做的最好的事情是在新程序仍然有旧程序的副本(exec之前)时调整新程序。

答案 1 :(得分: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();它看起来应该让你在这里做你需要的东西。

答案 2 :(得分:0)

您正在寻找的是进程间条件变量。 https://en.wikipedia.org/wiki/Monitor_(synchronization)

它的工作方式(大致): -

在分叉之前,你设置一个要求孩子等待的变量: - child_continue = false

1。)CHILD过程开始执行(或父项,无关紧要)

  • 如果变量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
  }
}