我必须在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 :(得分:2)
如果您的意思是任何代码,那可能会很困难。您可以将clone
与CLONE_STOPPED
而不是fork
一起使用来启动应用程序进入停止状态(需要SIGCONT再次启动它)。
但是,如果您只是指儿童中的特定代码并且您可以修改子代码,那么您可以main
中的第一件事就是为USR1
信号设置处理程序(任何IPC可能都会做,但在这个特殊情况下信号似乎最简单)然后等待它继续发射。
这样,进程本身就会运行,但还没有做任何事情。
然后让父母编织它需要做的任何魔法,然后将SIGUSR1发送给孩子。
但是,根据评论,你没有拥有访问客户端代码,第一个选项可能是最好的,假设SIGCONT
实际上不会导致问题和孩子在一起这将需要测试。
当然,要记住的一件事是,clone()
和fork()
实际上都不会将新的程序加载到子进程中,而这必须通过1}} - 在分割后调用。这是UNIX在exec
和fork
功能之间拆分的结果,详细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
}
}