使子进程等待父进程

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
}

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

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


使用管道,让子进程等待管道中的数据如何? - Vaughn Cato
你在父进程中打算用子进程的PID做什么?你能让被分叉的子进程在执行子应用程序之前等待父进程准备好吗?为什么不行? - Jonathan Leffler
3个回答

2
如果您指的是任何代码,那可能会很困难。您可以使用cloneCLONE_STOPPED代替fork将应用程序启动到停止状态(需要SIGCONT才能再次启动它)。
但是,如果您只是指子进程中的特定代码,并且可以修改子代码,则可以在main中的第一件事情是设置USR1信号的处理程序(任何IPC可能都可以,但在这种特殊情况下,信号似乎是最简单的),然后等待它触发才继续进行。
这样,进程本身将正在运行,但尚未执行任何操作。
然后,父进程可以进行任何必要的操作,然后向子进程发送SIGUSR1。
但是,根据评论,您没有访问客户端代码,因此,在假设SIGCONT不会实际上与子项产生问题的情况下,第一个选项可能是最佳选择。这将需要测试。
当然,需要记住的一件事是,clone()fork()都不会将您的新程序实际加载到子进程中,必须在拆分之后使用类似于exec的调用来完成。这是UNIX在forkexec功能之间的分裂的结果,详见此处
这意味着,虽然您无法控制子程序,但可以控制子进程,因此您的代码可以在加载新的子程序之前等待任何信号。因此,即使只使用fork(),也是可行的。
不幸的是,这也意味着clonefork都无法在使用exec加载新程序后停止您的进程(至少不能确定地),因此,如果要对新程序进行操作(例如通过附加到其内存来操作其变量),则无法执行此操作。
最好的办法是在新程序还有旧程序副本的时候(在exec之前)对新进程进行操作。

很遗憾,这不会起作用,因为我没有孩子代码的访问权限,所以无法在它的主方法中放置任何内容。 - Zac Reynolds
1
@Zac,那么你应该尝试使用clone选项。它仍然使用信号,但希望不需要访问源代码。可以通过在前台运行子进程,使用CTRL-Z停止它,然后使用fg重新启动它来轻松测试。如果它没有抱怨地生存下来,它应该可以使用clone/CLONE_STOPPED/SIGCONT工作。 - paxdiablo

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()的CLONE_VM标志;看起来它应该让您在这里做您所需的事情。


0
你需要的是进程间条件变量。 https://en.wikipedia.org/wiki/Monitor_(synchronization) 大致的工作方式如下:
在分叉之前,设置一个变量要求子进程等待: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
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接