如何强制 libusb 事件以便 libusb_handle_events() returns

How to force a libusb event so that libusb_handle_events() returns

假设我有一个只使用热插拔的 libusb 程序 API。您注册了一个回调,然后显然必须在一个循环中调用 libusb_handle_events(),然后循环调用您的热插拔回调。

int LIBUSB_CALL hotplugCallback(libusb_context* ctx,
                                libusb_device* device,
                                libusb_hotplug_event event,
                                void* user_data)
{
    cout << "Device plugged in or unplugged";
}

void main()
{
    libusb_init(nullptr);

    libusb_hotplug_register_callback(nullptr,
                                    static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
                                    LIBUSB_HOTPLUG_NO_FLAGS,
                                    LIBUSB_HOTPLUG_MATCH_ANY,
                                    LIBUSB_HOTPLUG_MATCH_ANY,
                                    LIBUSB_HOTPLUG_MATCH_ANY,
                                    &hotplugCallback,
                                    this,
                                    &hotplugCallbackHandle);

    for (;;)
    {
        if (libusb_handle_events_completed(nullptr, nullptr) != LIBUSB_SUCCESS)
            return 1;
    }

    return 0;
}

问题是,没有超时 hacks 我怎样才能干净地退出这个事件循环?我找不到任何将 libusb_handle_events()(或 libusb_handle_events_completed())强制为 return 的函数。理论上他们永远不会 return.

在函数中:

int libusb_handle_events_completed(libusb_context* ctx, int* completed) 

您可以将已完成的值更改为“1”,这样函数将return无阻塞

根据他们的文档:

If the parameter completed is not NULL then after obtaining the event handling lock this function will return immediately if the integer pointed to is not 0. This allows for race free waiting for the completion of a specific transfer.

libusb 中没有强制 libusb_handle_events() 到 return 的函数。

建议在专用线程中使用 libusb_handle_events(),这样您的主线程就不会被此调用阻塞。尽管如此,如果您需要操纵事件处理程序的调用,您可以将调用放在 while(condition) 中并在主线程中更改条件状态。

Libusb 文档对此进行了详细说明 here

对不起,如果晚了。

这个问题的措辞本来可以更好,但我假设(根据您的评论更新)您的实际程序与此类似:

int LIBUSB_CALL hotplugCallback(libusb_context *ctx,
                                libusb_device *device,
                                libusb_hotplug_event event,
                                void *user_data) {
    cout << "Device plugged in or unplugged";
}

void SomeClass::someFunction() {
    libusb_init(nullptr);
    libusb_hotplug_register_callback(nullptr,
                                static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
                                LIBUSB_HOTPLUG_NO_FLAGS,
                                LIBUSB_HOTPLUG_MATCH_ANY,
                                LIBUSB_HOTPLUG_MATCH_ANY,
                                LIBUSB_HOTPLUG_MATCH_ANY,
                                &hotplugCallback,
                                this,
                                &hotplugCallbackHandle);

    this->thread = std::thread([this]() {
        while (this->handlingEvents) {
            int error = libusb_handle_events_completed(context, nullptr);
        }
    });
}

假设您的对象正在被释放,并且无论 USB 总线上发生了什么,您都不关心并且您想要清理您的线程。

您否定 this->handlingEvents 并调用 thread.join(),线程挂起 60 秒,然后恢复执行。

这样做是因为 libusb_handle_events_completed 的默认行为调用 libusb_handle_events_timeout_completed 并传入 60 秒的超时间隔并计划使其无限。

你强制libusb_handle_events_completed到return的方式是你调用libusb_hotplug_deregister_callback唤醒向上 libusb_handle_events(),导致函数变为 return。

docs 中有关于此行为的更多信息。

因此 class 的析构函数(或任何您想立即停止收听的地方)可能看起来像这样:

SomeClass::~SomeClass() {
    this->handlingEvents = false;
    libusb_hotplug_deregister_callback(context, hotplugCallbackHandle);
    if (this->thread.joinable()) this->thread.join();

    libusb_exit(this->context);
}