Thread safety of NVENC calls when sharing D3D11 device context

I have a single ID3D11Device and ID3D11DeviceContext shared by different threads. Access to the ID3D11DeviceContext is protected by a mutex whereas access to the ID3D11Device is not, as per Introduction to Multithreading in Direct3D 11 - Win32 apps | Microsoft Learn.

Then I have the following (slightly simplified):

Thread A - captures video frame, copies to ID3D11Texture2D staging texture using device_context->map() - memcpy - device_context->unMap(). I then use device_context->copyResource to copy the contents of the staging texture to a default-usage texture suitable for passing to NVENC. It then pushes these textures to a thread-safe queue.

Thread B - takes a texture from the queue, registers it as a resource for NVENC, maps it as a registered resource, then submits it to encoder. It prevents the same texture from being re-used by Thread A until the encoder has produced the corresponding output for this frame, after which the texture is unmapped, unregistered, and made available for A again.

It mostly works, but I find I get a deadlock when I try and destroy and restart NVENC, while allowing the capture thread to continue. The deadlock occurs between Thread A calling device_context->map() on a staging texture (so not one that has or will be passed to the encoder) and Thread B calling nvEncOpenEncodeSessionEx.

It seems that I can stop it happening if I treat the call to nvEncOpenEncodeSessionEx as another access to the ID3D11DeviceContext and protect it with the same mutex, so I wanted to check that that is expected behaviour and that I should treat NVENC calls as requiring exclusive access to the ID3D11DeviceContext even though it doesn’t explicitly reference the ID3D11DeviceContext?

It’s possible something else is wrong with my code, but it would be helpful to understand whether the above is a correct summary?

I’ve checked and double-checked my code, fixed a few issues along the way, but inevitably without the mutex protection these two functions end up colliding sooner or later.

Its alway ends up stuck with Thread A inside device_context->map() and Thread B inside nvEncOpenEncodeSessionEx. It’s never any other functions.

These two functions seem like they have to serialised if they are using the same device/device context.

nvEncOpenEncodeSessionEx must be doing/locking something with the device/context that interferes with the map() call.