基本介绍

1. 关注进程状态变更

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

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

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

2. 进程的相互作用

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

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

3. 覆盖内置处理方法

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

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

4. 停止ev_child

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

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

相关函数

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

ev_child_set (ev_child *, int pid, int trace)

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

int pid [read-only]

表示关注的pid; 为0表示监视所有子进程.

int rpid [read-only]

表示检测到状态变更的子进程ID.

int rstatus [read-only]

导致的进程退出/跟踪状态.(更多内容请参阅sys/wait.hwaitpid的文档).

使用示例

启动子进程后在1秒后退出, 主进程收到退出后打印消息也退出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 只需导入单个头文件
#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;
}