让子进程等待父进程



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

如果你需要任何额外的信息,请问。谢谢。

编辑:我没有访问子代码的权限。我只是想运行一个可执行文件

如果您指的是任何代码,这可能很困难。你可以使用cloneCLONE_STOPPED而不是fork来启动应用程序进入停止状态(需要SIGCONT让它再次运行)。

然而,如果你只是指子代码中的特定代码,并且你可以修改子代码,你可以,作为main中的第一件事,简单地为USR1信号设置一个处理程序(任何IPC都可能这样做,但在这种特殊情况下信号似乎是最简单的),然后等待它在继续之前触发。

这样,进程本身将运行,但不会做任何事情。

然后让父进程编织它需要做的任何魔法,然后向子进程发送SIGUSR1。


但是,根据注释,您不访问客户端代码,第一个选项可能是最好的,假设SIGCONT实际上不会导致孩子的问题。这需要测试。


当然,要记住的一件事是,clone()fork()都不会实际将新的程序加载到子进程中,这必须在分割之后通过exec类型的调用来完成。这是UNIX在forkexec功能之间分离的结果,详细信息在这里。

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

不幸的是,这也意味着clonefork都不能在新程序加载exec之后停止进程(至少不是确定性的),所以,如果你想对新程序做的改动(比如通过附加到它的内存来操作它的变量),你不能这样做。

最好的方法是在新进程仍然有旧程序的副本(在exec之前)时对它进行修改。

有一种更简单的方法,假设您的操作系统允许您在子进程执行之前共享地址空间。伪代码如下所示。

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();它看起来应该让你在这里做你需要的。

您要查找的是进程间条件变量。https://en.wikipedia.org/wiki/Monitor_(同步)

工作方式(大致):-

在fork前设置一个变量让子进程等待:- child_continue = false

1)。子进程开始执行(或者父进程,不重要)

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

最新更新