如何知道句柄是否已经初始化

How to know if a handle has been already initialized

libuv中的句柄在使用前必须初始化。
它们都有一个关联的 uv_<handle>_init 函数。例如,uv_timer_t 有一个关联函数 uv_timer_init 来初始化它。

也就是说,我注意到如果我多次调用给定句柄的 init 函数,libuv 会出现未定义的行为。
一旦我关闭循环并执行一堆无效的 read/write 操作,它就会显示问题。
有没有办法知道句柄是否已经初始化?

例如,要知道句柄是关闭还是关闭,存在函数uv_is_closing.
有没有类似的函数可以知道句柄是否已经初始化?

uv_is_closing 的比较不太合适。 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 句柄都将包含非空指针,这不太可能以后有变化。

标记初始化句柄

如果我们不标记未初始化的对象,我们将不得不标记已初始化的对象。

保留已初始化句柄的列表。 Add/remove 个条目,就像你 initialize/close 个一样。


在内部,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);                                              \
  }                                                                           \

所以你最好自己跟踪它。

按照建议 here(实际上是 libev 的文档,但建议也适用于 libuv):

If you need more data and don't want to allocate memory separately and store a pointer to it in that data member, you can also "subclass" the watcher type and provide your own data:

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); 

And since your callback will be called with a pointer to the watcher, you can cast it back to your own type:

static void my_cb (struct ev_loop *loop, ev_io *w_, int revents) {
    struct my_io *w = (struct my_io *)w_;
    // ...
}

使用类似的方法,我们可以定义一个具有布尔参数的新结构,该参数指示它是否已被初始化。
在创建过程中将其设置为 false(工厂方法可以在此处提供帮助)并在初始化后将其切换为 true。

初始化句柄的句柄类型与 UV_UNKNOWN_HANDLE 不同,因此可以使用以下方法:

if (uv_handle_get_type(handle) != UV_UNKNOWN_HANDLE) {
...
}

或者,甚至可能

if (uv_handle_type_name(uv_handle_get_type(handle)) != NULL) {
...
}

因为这将检查 libuv.

是否知道相关句柄的类型