使用 C++11 异步时 Libusb 挂起

Libusb hangs when using C++11 async

我是libusb的新手,所以不是很了解。我正在尝试进行一些 USB 通信。

我正在使用效果很好的热插拔功能。所以我想当我检测到设备到达事件时,我会使用 C++11 异步功能在另一个线程上与 USB 进行所有通信,这样我就可以与多个设备进行同步 I/O 以简化代码。他们的异步 I/O 让我有点困惑。希望我可以使用同步 I/O 和 C++ 异步功能。

但我遇到了一个问题,当代码为 C++11 异步功能中的 运行 时,某些 libusb 调用似乎挂起。当它不是 C++11 异步功能中的 运行 时,它可以正常工作。

所以我假设问题出在我的 C++11 异步功能代码上。

这是我的热插拔回调:

int LIBUSB_CALL hotplug_callback(libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data)
{
  std::future<void> result(std::async([] (libusb_device *d) {

    libusb_device_handle *h;

    printf("%s\n", "Opening");
    int rc = libusb_open(d, &h);
    if(rc != LIBUSB_SUCCESS) {
      printf("ERROR: %s\n", libusb_error_name(rc));
      return;
    }
    printf("%s\n", "Opened");

    printf("%s\n", "Closing");
    libusb_close(h);
    printf("%s\n", "Closed!");

  }, dev));

  result.get();

  return 0;
}

因此使用此代码它挂在 libusb_close

它输出:

Opening
Opened
Closing

主要代码如下所示:

int main(int argc, char* argv[]) {

  int vendor_id = 0x1234;
  int product_id = 0x4556;

  libusb_hotplug_callback_handle *hp = nullptr;
  libusb_context *context = nullptr;
  int rc = libusb_init(&context);

  if(rc < 0)
  {
    return rc;
  }

  libusb_set_debug(context, LIBUSB_LOG_LEVEL_WARNING);

  rc = libusb_hotplug_register_callback(
    context,
    LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
    LIBUSB_HOTPLUG_NO_FLAGS,
    vendor_id,
    product_id,
    LIBUSB_HOTPLUG_MATCH_ANY,
    hotplug_callback,
    NULL,
    hp
    );

  if (LIBUSB_SUCCESS != rc) {
    libusb_exit (context);
    return rc;
  }

  while(1) {
    rc = libusb_handle_events(context);
  }

  return 0;
}

请注意,这段代码比较典型,所以写得不是很好。还在libusb的探索模式中。

According to their own website,使用 libusb 的多线程(如果不序列化,std::async 本质上就是多线程)需要考虑很多。

例如,他们明确指出:

libusb_close() will remove a file descriptor from the poll set. There are all kinds of race conditions that could arise here, so it is important that nobody is doing event handling at this time.

在您的代码中,一个线程中对 libusb_close 的调用与另一个线程中对 libusb_handle_events 的调用之间没有同步。相关(来自与上述相同的来源):

The issue is that if two or more threads are concurrently calling poll() or select() on libusb's file descriptors then only one of those threads will be woken up when an event arrives. The others will be completely oblivious that anything has happened.

完全可以想象,这里发生的是主线程中的libusb_handle_events是"stealing"一个libusb_close正在等待的事件,使得它永远不会return .

底线是您需要:

  1. 关注链接文章,其中详细解释了如何将 libusb 与多线程一起使用,或者
  2. 了解 libusb 的异步 API 并加以利用。