在 libev 事件回调函数中调用阻塞函数是否会阻塞整个应用程序?
Does calling a blocking function inside libev event callback function blocks whole app?
我使用 libev 开发我的事件驱动应用程序。我喜欢查询远程 mysql 服务器内部事件。所以,
mysql_real_connect 阻止整个应用程序或只是 my_read_cb
根据以下代码
my_read_cb(EV_P_ ev_io *w, int revents) {
mysql_real_connect(*mysql, "host", "user", "pass", "db", 3306, NULL, 0);
}
struct ev_loop *loop = ev_default_loop(0);
ev_io_init(io, my_read_cb, network_fd, EV_READ);
ev_io_start(loop, io);
ev_run(loop, 0);
它阻塞了整个应用程序,因为回调函数 my_read_cb()
与 ev_run()
函数在同一个(也称为主)线程中执行。
这就是 reactor pattern 的工作方式,您的代码应该是 "non-blocking" 这意味着您应该避免任何 I/O 等待、sleep()
调用、互斥等待等。很难遵循这样的来自各种库的传统阻塞代码的要求,例如您的情况下的 MySQL 驱动程序。
有(至少)三种解决方法:
- 接受事件循环时不时被阻塞的事实。在某些应用程序中可能不是什么大问题。
- 实施proactor pattern - that basically means that each handler callback is executed in a worker thread different from a main thread and for that reason, the event loop is not blocked. This is what Node.js provides or in C world libuv等等。
- 找到与您的事件循环兼容的库的 asynchronous/non-blocking 实现。你需要在这里特别幸运。一个例子是例如https://c-ares.haxx.se 用于异步 DNS 解析(与
getaddrinfo
系列中的 POSIX 系统 DNS 阻止调用相反)。
我使用 libev 开发我的事件驱动应用程序。我喜欢查询远程 mysql 服务器内部事件。所以, mysql_real_connect 阻止整个应用程序或只是 my_read_cb
根据以下代码
my_read_cb(EV_P_ ev_io *w, int revents) {
mysql_real_connect(*mysql, "host", "user", "pass", "db", 3306, NULL, 0);
}
struct ev_loop *loop = ev_default_loop(0);
ev_io_init(io, my_read_cb, network_fd, EV_READ);
ev_io_start(loop, io);
ev_run(loop, 0);
它阻塞了整个应用程序,因为回调函数 my_read_cb()
与 ev_run()
函数在同一个(也称为主)线程中执行。
这就是 reactor pattern 的工作方式,您的代码应该是 "non-blocking" 这意味着您应该避免任何 I/O 等待、sleep()
调用、互斥等待等。很难遵循这样的来自各种库的传统阻塞代码的要求,例如您的情况下的 MySQL 驱动程序。
有(至少)三种解决方法:
- 接受事件循环时不时被阻塞的事实。在某些应用程序中可能不是什么大问题。
- 实施proactor pattern - that basically means that each handler callback is executed in a worker thread different from a main thread and for that reason, the event loop is not blocked. This is what Node.js provides or in C world libuv等等。
- 找到与您的事件循环兼容的库的 asynchronous/non-blocking 实现。你需要在这里特别幸运。一个例子是例如https://c-ares.haxx.se 用于异步 DNS 解析(与
getaddrinfo
系列中的 POSIX 系统 DNS 阻止调用相反)。