libuv
中的句柄必须在使用前初始化
它们都具有相关的uv_<handle>_init
功能。例如,uv_timer_t
有一个关联函数uv_timer_init
来初始化它。
那就是说,如果我多次调用给定句柄的init函数,我注意到libuv
有一个未定义的行为。
一旦我关闭循环并执行一堆无效的读/写操作,它就会显示问题
有没有办法知道手柄已经初始化了?
例如,要知道句柄是关闭还是关闭,则存在函数uv_is_closing
。
是否有类似的函数来知道句柄是否已经初始化?
答案 0 :(得分:2)
与uv_is_closing
的比较并不合适。关闭时,关闭可以设置一点,您可以稍后检查。但是当没有任何功能触及手柄时,您期望检查什么?
然而,有一些解决方法:
将句柄显式归零:memset(&handle, 0x00, sizeof handle)
。要确定句柄是否未初始化,请检查它是否仍为全字节零:
int is_all_zeroes(void *buf, size_t len) {
for (unsigned char *p = buf; p < buf + len; p++) {
if (*p != 0x00)
return 0;
}
return 1;
}
这个假设全零句柄不能是有效的对象,这是一个安全的赌注,因为任何初始化的libuv句柄都将包含非空指针,这在将来不太可能改变。 / p>
如果我们不标记未初始化的对象,我们将必须标记已初始化的对象。
保留已初始化句柄的列表。在初始化/关闭条目时添加/删除条目。
在内部,libuv已经标记了初始化句柄。初始化句柄时,会将其添加到uv_loop_t
特定QUEUE
。
此 API并非公开,但是:
#define uv__handle_init(loop_, h, type_) \
do { \
(h)->loop = (loop_); \
(h)->type = (type_); \
(h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
uv__handle_platform_init(h); \
} \
所以你最好自己跟踪它。
答案 1 :(得分:0)
根据建议automatic variable(实际上是libev
的文档,但该建议也适用于libuv
):
如果您需要更多数据并且不想单独分配内存并在该数据成员中存储指向它的指针,您还可以“子类化”观察者类型并提供您自己的数据:
struct my_io { ev_io io; int otherfd; void *somedata; struct whatever *mostinteresting; }; // ... struct my_io w; ev_io_init (&w.io, my_cb, fd, EV_READ);
由于您的回调将使用指向观察者的指针进行调用,因此您可以将其转换回您自己的类型:
static void my_cb (struct ev_loop *loop, ev_io *w_, int revents) { struct my_io *w = (struct my_io *)w_; // ... }
使用类似的方法,我们可以定义一个具有布尔参数的新结构,该结构指示它是否已经初始化。
在创建过程中将其设置为false(工厂方法可以在这里提供帮助),并在初始化后将其切换为true。