Skip to content

Multi‐threading Notes

Ihor Dutchak edited this page Jan 23, 2025 · 2 revisions

General statement

HIDAPI v0.x.x is not thread-safe.

There are a few specific cases that softens the above statement and this document describes those from the most strict to least strict.

Some of the HIDAPI functions may be used from different threads and the below describes in which cases.

Initialisation / enumeration

hid_init/hid_exit/hid_enumerate/hid_open/hid_open_path/hid_close/hid_error(NULL) shall not be called concurently from different threads. Yes, in general case, it is not even safe to open different devices in different threads concurently.

One of the reasons is that in case of any of those function fails - a global error string will be updated (which can be accessed with hid_error(NULL)).

NOTE: if hid_init is never called explicitly, it is called implicitly by each of hid_enumerate/hid_open/hid_open_path.

macOS: on macOS there is even stricter requirement: hid_init and hid_exit has to be called from the same thread. See #666 for discussion. And the thread where hid_init has been called should not be exited until all HIDAPI devices are closed and hid_exit is called.

Multiple devices

All functions that accept hid_device as a first argument are to be referenced as a "device functions".

All device functions are thread-unsafe, but may be used from different threads on different devices. I.e. same HIDAPI device cannot be accessed concurently with any of the device function, but different devices can be accessed from different threads (i.e. a dedicated thread per-device).

hid_close is the exception here - it should be serialized with initialisation/enumeration functions described in the previous section.

hid_read

Even though it is perfectly safe to have a separate thread to handle a specific hid_device it is often desirable to have a another dedicated thread to handle hid_read/hid_read_timeout specifically.

NOTE: it is almost impossible to use hid_read in real-world scenarios and handle some of the errors/corner cases correctly, until #146 is implemented (see #133), but for simplicity in this document hid_read would most likey imply the usage of hid_read_timeout instead.

Many projects successfully using one thread for hid_read and another thread for all other device functions. That is the only way of using HIDAPI device in such manner, and it works fine most of the time.

The problem starts for backends that implement hid_error. In case of an error, the internal error string buffer (which later used by hid_error) can be concurently accessed from different threads causing undefined behavior. An attemt was made to reference this issue, but not yet accepted as a solution.

So as of this moment (v0.14.0), it is strictly safe to have a separate thread for hid_read only when using libusb backend of HIDAPI as it is the only backend that doesn't have hid_error implemented.

Clone this wiki locally