Libusb在使用C++11异步时卡住了。

3
我对libusb很陌生,所以并不是非常理解它。我正在尝试进行一些USB通信。
我正在使用热插拔功能,这个功能运行得相当好。因此,我想当我检测到设备到达事件时,在另一个线程上使用C++11异步特性进行所有与USB的通信,以便我可以使用同步I/O与多个设备简化代码。他们的异步I/O有点令人困惑。希望我能够使用C++异步特性进行同步I/O。
但是,我遇到了一个问题,一些libusb调用似乎在C++11异步特性中运行时会挂起。当它没有运行在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 的探索阶段。
1个回答

4

根据他们自己的网站,使用多线程和libusb(如果未串行化,则std::async本质上是多线程)需要考虑很多因素。

例如,他们明确指出:

libusb_close()将从轮询集中删除文件描述符。这里可能会出现各种竞态条件,因此重要的是此时没有人进行事件处理。

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

问题在于,如果两个或更多线程同时在libusb的文件描述符上调用poll()或select(),则只有其中一个线程在事件到达时会被唤醒。其他人将完全不知道发生了任何事情。

完全可以想象,在这里发生的是主线程中的libusb_handle_events“窃取”了libusb_close正在等待的事件,使其永远不会返回。

“底线是你需要做以下两个选项之一:
1.阅读链接的文章,该文章详细解释了如何使用带有多线程的libusb;
2.理解libusb的异步API,并使用它来代替。”

谢谢,最终我选择了他们的异步API。 - pdiddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接