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

时间:2016-10-04 20:20:44

标签: c++ multithreading c++11 libusb-1.0

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

我正在使用效果很好的热插拔功能。所以我想当我检测到设备到达事件时,我会使用C++11异步功能在另一个线程上与USB进行所有通信,因此我可以使用多个设备进行同步I / O以简单编码。他们的异步I / O对我来说有点混乱。希望我可以使用具有C ++异步功能的同步I / O.

但是我遇到一个问题,当代码在C ++ 11异步功能中运行时,某些libusb调用似乎挂起了。当它没有在C ++ 11异步功能中运行时,它没有任何问题。

所以我假设这是我的C ++ 11异步功能代码就是问题。

这是我的hotplug回调:

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 个答案:

答案 0 :(得分:3)

According to their own website,使用带有libusb的多线程(如果没有序列化,则std::async本质上是多线程的)需要相当多的考虑。

例如,他们具体说明:

  

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

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

  

问题是如果两个或多个线程同时在libusb的文件描述符上调用poll()或select(),那么当事件到达时,这些线程中只有一个会被唤醒。其他人将完全忘记发生任何事情。

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

最重要的是你需要:

  1. 按照链接文章进行操作,该文章详细说明了如何将libusb与多线程一起使用,或者
  2. 了解libusb的异步API并改为使用它。