Skip to content

Use standard C++ for DeviceThreadBase and MMThreadLock implementation - #973

Merged
marktsuchida merged 6 commits into
micro-manager:mainfrom
marktsuchida:fix-device-thread-leak
Jul 20, 2026
Merged

Use standard C++ for DeviceThreadBase and MMThreadLock implementation#973
marktsuchida merged 6 commits into
micro-manager:mainfrom
marktsuchida:fix-device-thread-leak

Conversation

@marktsuchida

@marktsuchida marktsuchida commented Jul 18, 2026

Copy link
Copy Markdown
Member

Closes #971.

Retire the Win32 and pthreads types/calls and replace with std::thread and std::recursive_mutex.

No longer leak a thread handle (Windows) or joinable thread (POSIX).

Patch device adapters that broke because MMDevice no longer includes Windows.h or defines WIN32_LEAN_AND_MEAN.

No device ABI changes. Source-incompatible changes (no in-tree adapters affected):

  • DeviceThreadBase::activate() is no longer virtual and now returns void rather than int (no adapter overrides this function or reads its return value)
  • MMThreadGuard::isLocked() has been deleted (no adapter calls it)

TODO:

  • Patch device adapters (if any) that break because pthread.h is no longer included by MMDevice

On Windows, the handle returned from CreateThread() must be closed; we
were leaking it. On POSIX, we need to either join or detach the thread,
or else the kernel keeps a record of the thread until process exit.

In addition to plugging those leaks (by detaching in the destructor),

- Also avoid a similar leak when re-activating
- Fail early and definitely on double-join (a programming error)
- Change activate() to return void and make non-virtual (no code in our
  codebase uses the return value or overrides activate())
- Use modern way to disable copy/move construction/assignment (= delete)
Much simpler.

Behavioral changes: errors now throw rather than silently continue or
terminate. In practice this is probably a good thing: typical callers
won't swallow exceptions and we'll crash with "uncaught C++ exception",
which is better than continuing or terminating with no information. In
any case errors are either programming errors or rare resource
exhaustions.
Not used, and cannot think of a valid use case. Note that
std::lock_guard has no analogous function.
Previously ignored (rare) errors will now throw.
No longer needed in DeviceThreads.h, now that we use standard C++
thread/mutex.

Lots of device adapters relied on transitive inclusion (including via
DeviceBase.h, which includes DeviceThreads.h), so required fixing.

In some cases, defining `WIN32_LEAN_AND_MEAN` was the critical part (to
prevent Windows.h from defining `byte`, which clashes with C++17
`std::byte` if `using namespace std` is used). This includes the MCCDAQ
vendor header which includes Windows.h.

For IntegratedLaserEngine, a member function GetCurrentTime had to be
renamed, because Windows.h defines a macro of that name. The reason it
was working previously was that all occurrences of GetCurrentTime were
being replaced by the same name (GetTickCount), but that was extremely
fragile.

Some additional cleanup of #includes and adjacent directives is
included.
@marktsuchida
marktsuchida force-pushed the fix-device-thread-leak branch from d9bb064 to 996540c Compare July 20, 2026 20:42
@marktsuchida

Copy link
Copy Markdown
Member Author

There were no missing pthread.h includes in device adapters, as far as I can easily test, on macOS (official build) and Linux (best-effort). Not surprising because (unlike Windows.h) it's only needed for threading. Also, libstdc++/libc++ appear to leak pthread.h from <thread> and others, so we likely cannot break existing code by this #include removal in practice.

@marktsuchida
marktsuchida marked this pull request as ready for review July 20, 2026 21:01
@marktsuchida
marktsuchida merged commit 35b3cef into micro-manager:main Jul 20, 2026
16 checks passed
@marktsuchida
marktsuchida deleted the fix-device-thread-leak branch July 20, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MMDeviceThreadBase leaks Win32 thread handle

1 participant