-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDeviceThreads.h
More file actions
148 lines (127 loc) · 4.13 KB
/
Copy pathDeviceThreads.h
File metadata and controls
148 lines (127 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
///////////////////////////////////////////////////////////////////////////////
// FILE: DeviceThreads.h
// PROJECT: Micro-Manager
// SUBSYSTEM: MMDevice - Device adapter kit
//-----------------------------------------------------------------------------
// DESCRIPTION: Cross-platform wrapper class for using threads in MMDevices
//
// AUTHOR: Nenad Amodaj, nenad@amodaj.com 11/27/2007
// COPYRIGHT: University of California, San Francisco, 2007
// LICENSE: This file is distributed under the BSD license.
// License text is included with the source distribution.
//
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
#pragma once
#include <mutex>
#include <thread>
/**
* @brief Base class for threads in MM devices.
*
* @attention New code should use std::thread instead.
*/
class MMDeviceThreadBase
{
public:
MMDeviceThreadBase() {}
virtual ~MMDeviceThreadBase()
{
// Detaching on destruction may not be the ideal design, but the only one
// possible given previous behavior (which leaked the native handle).
if (thread_.joinable())
thread_.detach();
}
// Cannot copy a thread
MMDeviceThreadBase(const MMDeviceThreadBase&) = delete;
MMDeviceThreadBase& operator=(const MMDeviceThreadBase&) = delete;
// We also cannot safely support move because the thread calls svc() by
// reference.
MMDeviceThreadBase(MMDeviceThreadBase&&) = delete;
MMDeviceThreadBase& operator=(MMDeviceThreadBase&&) = delete;
/**
* @brief This function is called on the new thread.
*
* The return value is ignored.
*/
virtual int svc() = 0;
void activate()
{
if (thread_.joinable())
thread_.detach();
thread_ = std::thread([this]() { (void)svc(); });
// Note: failure to create the thread will throw std::system_error, but
// that only happens upon resource exhaustion (normally rare; akin to
// std::bad_alloc). Most callers do not handle this, but terminating with
// an uncaught exception is preferable to silently continuing (as we
// previously did).
}
void wait()
{
// Note: joining a non-joinable thread (a programming error) will throw
// std::system_error.
thread_.join();
}
private:
std::thread thread_;
};
/**
* @brief Critical section lock.
*
* @attention New code should use std::mutex or std::recursive_mutex instead
* (note that MMThreadLock is recursive).
*/
class MMThreadLock
{
public:
MMThreadLock() = default;
// Disallow moving because we always did and no reason to newly allow.
~MMThreadLock() = default;
MMThreadLock(const MMThreadLock&) = delete;
MMThreadLock& operator=(const MMThreadLock&) = delete;
MMThreadLock(MMThreadLock&&) = delete;
MMThreadLock& operator=(MMThreadLock&&) = delete;
void Lock()
{
mutex_.lock();
}
void Unlock()
{
mutex_.unlock();
}
private:
std::recursive_mutex mutex_;
};
/**
* @brief RAII object to acquire and auto-release MMThreadLock.
*
* @attention New code should use std::lock_guard instead.
*/
class MMThreadGuard
{
public:
MMThreadGuard(MMThreadLock& lock) : lock_(&lock)
{
lock_->Lock();
}
MMThreadGuard(MMThreadLock* lock) : lock_(lock)
{
if (lock != nullptr)
lock_->Lock();
}
~MMThreadGuard()
{
if (lock_ != nullptr)
lock_->Unlock();
}
MMThreadGuard(const MMThreadGuard&) = delete;
MMThreadGuard& operator=(const MMThreadGuard&) = delete;
MMThreadGuard(MMThreadGuard&&) = delete;
MMThreadGuard& operator=(MMThreadGuard&&) = delete;
private:
MMThreadLock* lock_;
};