【问题标题】:Launching Asynchronous Processes using C in *nix在 *nix 中使用 C 启动异步进程
【发布时间】:2012-04-01 23:49:34
【问题描述】:

我有这样的情况:

start();
<Some code>
end();

我希望start() 函数启动一个异步执行某些操作的进程(而不是单独的线程)(我的意思是在生成进程后立即,控件应该返回父进程并且生成的进程进入“后台”)父进程,然后在&lt;Some code&gt; 块完成后,end() 函数将killstart() 关联的进程ID。 我不知道该怎么做,尤其是使父子代码块异步的部分;需要一些帮助。谢谢。

编辑:在得到成员的帮助后,我能够编写这段代码,但这有问题,如果有人能指出错误,那就太好了。我想要_do_() 只是启动一个子进程,如果_stop_() 无法杀死它,它就永远不会结束。但是由于某种原因,父进程迷路了,程序在while()循环上无限期地运行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <signal.h>
#include <errno.h>

pid_t id = 0;

int _do_()
{
//int status;
pid_t childpid; /* variable to store the child's pid */
FILE *fp= NULL;
childpid = fork();

//child stuff
if (childpid == 0) 
{
    id = getpid();
    fp = fopen ("Log.txt", "w+");
    while (1)
    {
        fprintf(fp, "Logging info...\n");
        fflush(fp);
    }
    fclose(fp);
}

if (childpid < 0) /* fork returns -1 on failure */
{
    perror("fork"); /* display error message */
    exit(-1); 
}

 return 0;

}

 //kill child process in _do_()
 int _stop_()
 {
  int en;
  printf("Going to kill child ID: %d\n", id);
  if (kill ( id , SIGKILL ) < 0)
  {
    en = errno;
    printf("Error while trying to KILL process: %s\n", strerror(en));
  }
  printf("Logging ended\n");

    return 0;

 }

 int main(int argc, char* argv[])
 {
   int i;

   _do_();
   for (i = 0; i < 200; i++)
    ;
   _stop_();
   printf("\nEnded...\n");
   return 0;
}

EDIT2:我不能做我想做的事,从end() 杀死一个从start() 开始的进程,而是启动一个守护进程并让它转储文件上的值,直到文件大小达到某个预先指定的限制.这是最接近我想要的。

【问题讨论】:

  • this SO question - 它包括实现start的代码,它要求end的代码。
  • 请在答案中查看我的第二次编辑,我提到了为什么你的 kill 没有杀死进程。

标签: c process signals


【解决方案1】:

你想找到一些关于 fork/exec/kill 如何工作的示例。

通常你 fork 一个进程,它创建两个进程:一个子进程和一个父进程。子进程从“fork”返回,返回代码为 0。父进程返回子进程的 pid - 这就是你如何知道你是在子进程还是父进程。

现在如果你想执行一些其他程序,你可以从子进程调用'exec'。但是,您也可以使用以下代码:

pid = fork();
if (pid == 0)
{
  // do child stuff here
  exit (0);
}
if (pid == -1)
 // failed to fork, deal with it

// parent code goes here
...
...
kill(pid, SIGKILL); // you can kill your child process here if you want to.
                    // thanks to Adam Rosenfield for pointing out the signal number has to be sent

看一下教程就很简单了。 Windows 的工作方式不同,因此如果您想将代码移植到 Windows,请同时使用 fork 和 exec,因为 Windows 实际上不会创建相同的程序副本 - 它实际上总是会生成一个新程序。

我相信,不要引用我的话,Windows 程序员比 unix 程序员更倾向于使用线程——因为在 Windows 上创建一个新进程是一件大事。在 unix 上,这没什么大不了的,但它比线程更重要。但是线程编程要困难得多,相比之下,你可能想远离它,除非你真的需要它。

编辑: 在执行 'kill(pid, SIGKILL)' 之前,您真的想确保您的孩子还活着。如果您的孩子死了,该 pid 可能已被另一个进程重用,在这种情况下,您可能会终止某个随机进程。

编辑2: 您的代码中存在错误。

1 - remove 'int id...'
2 - move pid_t childpid; from function into global scope
3 - kill childpid, not 'id'

【讨论】:

  • +1,但为了迂腐,它是kill(pid, SIG)(不是kill(pid)),其中SIG 是您要发送的信号的名称,在这种情况下可能是SIGKILL
  • 我有一个问题,在 start() 中,我有两个部分,一个给孩子另一个给父母,我从父母退出,但不是从孩子。然后稍后,在end() 我发出kill(pid, SIGKILL) 其中pid 是一个全局变量,以便我得到孩子的pid。但不知怎的,孩子还活着……
  • 嗯,SIGKILL 无论如何都应该杀死进程(不能忽略那个)。确保你的 'pid' 是 pid_t 类型,而不是 'int'。
  • 实际上直到stop() 才到达,我在子块上有一个while(1){//append file},它正在无限运行。
【解决方案2】:

在“// do child stuff here”部分中,您可能会再次分叉并终止原始子进程,让孙子进程继续,但现在由 init 程序(进程 ID 1)继承。像这样的:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

void OutputPids(const char *tag)
{
    printf("in %s process %d, parent is %d\n", tag, getpid(), getppid());
}

int main(int ac, char **av)
{
    pid_t pid_child = -1;
    OutputPids("original");
    if(-1 == (pid_child = fork())) {
        perror("fork (for child)");
    } else if(0 == pid_child) {     /* fleeting child process */
        pid_t pid_grandchild = -1;
        if(-1 == (pid_grandchild = fork())) {
            perror("fork (for granchchild)");
        } else if(0 == pid_grandchild) { /* in grandchild */
            int i;
            setsid();
            setpgid(0, 0);
            for(i = sysconf(_SC_OPEN_MAX) ; i > 3 ; --i)
                close(i);  // close any stray filedescriptors
            OutputPids("grandchild(ready)");
            // run the rest of the command line as a asynch command
            execvp(av[1], av + 1);
            perror("execvp");
            exit(1);
        }
        OutputPids("child(suiciding)");
        _exit(0);           /* skip atexit processing, etc. */
    } else  {                   /* original process */
        OutputPids("original(waiting)");
        wait(pid_child);                /* wait for child to die (quick) */
    }
    OutputPids("original(after fork)");
    // stuff for your main routine continues here...
    sleep(2);
    OutputPids("original(done)");
    return 0;
}

示例运行:

$ ./doublefork echo GRANDCHILD OUTPUT
in original process 13414, parent is 22338
in original(waiting) process 13414, parent is 22338
in child(suiciding) process 13415, parent is 13414
in original(after fork) process 13414, parent is 22338
in grandchild(ready) process 13416, parent is 1
GRANDCHILD OUTPUT
in original(done) process 13414, parent is 22338
$

【讨论】:

    猜你喜欢
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多