ev_child

关注进程状态变更

当您因为子进程状态变更而收到SIGCHLD的时候, 注册的ev_child则会触发.

在进入事件循环之前调用fork后注册ev_child, 然在运行事件循环期间就可以工作的很好. 但如果在运行时间循环期间fork后在注册ev_child则不行.

并且, 只有默认事件循环能够处理此信号, 因此只能在默认事件循环中注册ev_child。

进程的相互作用

一旦默认的事件循环初始化, Libev就能捕获到SIGCHILD. 即使第一个子进程退出后才启动ev_child, 这样中初始化顺序对保证正确性重要.

SIGCHLD的接收一定是异步的. 但是为了让其作为事件循环一部分, 进程状态获取则是同步的. Libev会接收到所有子进程的信号, 无论您是否关注它们的状态.

覆盖内置处理方法

Libev没有提供重写内置SIGCHILD处理的特殊支持, 虽然您可以通过自行注册SIGCHILD处理程序.

但是我建议您最好使用Libev基于事件的机制来处理, 这样您不必再为单独为它做额外的工作了.

停止ev_child

目前为止! 即使子进程终止或者退出ev_child也不会主动退出, 通常需要手动调用来停止运行.

但是在未来的版本可能会在检测的子进程退出后自动停止ev_child, 并且ev_child_stop调用多次不是问题.

相关函数

ev_child_init (ev_child *, callback, int pid, int trace);

// 配置ev_child观察pid指向的子进程ID的状态变化.
// 可以在回调函数里通过观察rstatus成员来查看状态(使用sys/wait.h中的宏并查看您的系统waitpid文档),
// rpid成员包含了导致变换的进程ID. trace则必须是0或者1.
// trace为0表示仅关注进程终止的状态.
// trace为1表示仅关注进程暂停、继续的状态.
ev_child_set (ev_child *, int pid, int trace);

// 表示关注的pid; 为0表示监视所有子进程.
int pid [read-only]

// 表示检测到状态变更的子进程ID.
int rpid [read-only]

// 导致的进程退出/跟踪状态.(更多内容请参阅sys/wait.h与waitpid的文档).
int rstatus [read-only]

示例

// 只需导入单个头文件
#include <ev.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// 当使用了键盘的组合键`CTRL`+`C`之后回调会被调用.
static void child_cb (struct ev_loop *loop, ev_child *w, int revents)
{
  printf("Loop ot ProcessID: %d, Process status: %d\n", w->rpid, w->rstatus);
  ev_break(loop, EVBREAK_ALL);
}


int main (void)
{

  // 调用`fork`创建并分离父子进程
  int id = fork();
  if (id == -1) {
    puts ("Failed to create child process.");
    exit(EXIT_FAILURE);
  }

  // 如果id == 0就是子进程.
  if (!id) {
    sleep(1);
    puts("Child process exit.");
    exit(EXIT_SUCCESS);
  }

  // 可以使用已定义的宏来获取默认的事件循环, 当然你也可以根据自己的需求创建指定的.
  struct ev_loop *loop = EV_DEFAULT;

  ev_child child;
  ev_child_init(&child, child_cb, 0, 0);
  ev_child_start(loop, &child);

  // 开始运行事件循环
  ev_run (loop, 0);

  // 如果事件循环退出, 那将会执行到这里.
  return 0;
}