使用C in * nix启动异步进程

时间:2012-04-01 23:49:35

标签: c process signals

我有这样的情况:

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

我希望start()函数启动一个异步执行某个过程的进程(不是单独的线程)(我的意思是在生成进程后立即执行,控件应返回到父进程,并且生成的进程进入'后台' )使用父进程,然后在<Some code>阻止完成后,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:我无法做我想做的事情,从start()杀死从end()开始的进程,而是启动一个守护进程并让它将值转储到文件上,直到文件大小到达某些文件预先指定的限制。这是我想要的最近的。

2 个答案:

答案 0 :(得分:4)

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

通常你会分叉一个进程,它会创建两个进程:子进程和父进程。子进程从'fork'返回,返回码为0.父进程返回child的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上,它不是一个大交易,但它比一个线程更重要。但是线程编程要困难得多,相比之下,你可能希望远离它,除非你真的需要它。

编辑: 在做'杀戮(pid,SIGKILL)'之前,你真的想确保你的孩子还活着。如果你的孩子死了,pid可能会被另一个进程重用,在这种情况下你可以终止一些随机过程。

EDIT2: 您的代码中存在错误。

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

答案 1 :(得分:1)

在“// 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
$