我想在基于遗留参考代码的 C++ 程序中为正在运行的线程实现单锁。
void AutoThread::CreateEvent()
{
AutoRunning = new CRtEvent(FALSE, TRUE,"AutoRunning");
AutoHoming = new CRtEvent(FALSE, TRUE,"AutoHoming");
AutoPicking = new CRtEvent(FALSE, TRUE,"AutoPicking");
AutoMoving = new CRtEvent(FALSE, TRUE,"AutoMoving");
}
int AutoThread :: Run()
{
while (1) {
CRtSingleLock sSingleLock132(AutoRunning, FALSE);
CRtSingleLock sSingleLock134(AutoPicking, FALSE);
CRtSingleLock sSingleLock144(AutoHoming, FALSE);
CRtSingleLock sSingleLock154(AutoMoving, FALSE);
if(sSingleLock132.Lock(0) || ( sSingleLock134.Lock(0)) ||
( sSingleLock144.Lock(0)) || sSingleLock154.Lock(0)) {...}
}
}
`
但是,由于我使用的是主要支持标准C++ API的专有软件,单锁机制不可用。我已经了解了一些可用的同步函数,例如临界区、互斥量和信号量,但我仍然对使用什么来替代单锁感到困惑。
欢迎对我的问题提出任何意见和建议;因为我是多线程概念和线程之间的资源共享的新手。
使用一个条件变量等待状态变化而不是有 4 个单独事件的示例。
在线演示:https://onlinegdb.com/J8nrlkIo3x
如果有任何问题,请告诉我
// state_synchronization header
#include <mutex>
#include <condition_variable>
#include <chrono>
// class to synchronize states between threads
// using condition variables.
template<typename type_t>
class state_synchronization_t final
{
public:
explicit state_synchronization_t(const type_t& state) :
m_state{ state },
m_cancelled{ false }
{
}
~state_synchronization_t()
{
// be nice at shutdown
cancel_waits();
}
//non copyable/non movable
state_synchronization_t(const state_synchronization_t&) = delete;
state_synchronization_t& operator=(state_synchronization_t&) = delete;
state_synchronization_t(state_synchronization_t&&) = delete;
state_synchronization_t& operator=(state_synchronization_t&&) = delete;
// at shutdown of the system any pending waits must be aborted
// so that waiting threads get unblocked.
void cancel_waits()
{
std::unique_lock<std::mutex> lock(m_state_mutex);
m_cancelled = true;
m_state_changed.notify_all();
}
void set(const type_t& state)
{
std::unique_lock<std::mutex> lock(m_state_mutex);
m_state = state;
m_state_changed.notify_all();
}
// wait for a state change or cancelled
bool wait_for(const type_t& state, const std::chrono::steady_clock::duration& duration)
{
std::unique_lock<std::mutex> lock(m_state_mutex);
auto retval = m_state_changed.wait_for(lock, duration, [&] { return (m_state == state) || m_cancelled; });
if (m_cancelled) throw std::runtime_error("cancelled");
return retval;
}
private:
std::mutex m_state_mutex;
std::condition_variable m_state_changed;
std::atomic<type_t> m_state;
bool m_cancelled;
};
// main cpp file
#include <future>
#include <iostream>
using namespace std::chrono_literals;
// use 1 enum instead of 4 synchronization primitives to model states
enum class motion_state_v
{
unknown,
running,
homing,
picking,
moving
};
int main()
{
// initialize state
state_synchronization_t<motion_state_v> state{ motion_state_v::unknown };
[[maybe_unused]] auto future = std::async(std::launch::async,[&]
{
std::cout << "background thread : homing\n";
state.set(motion_state_v::homing);
std::this_thread::sleep_for(250ms);
std::cout << "background thread : running\n";
state.set(motion_state_v::running);
});
std::cout << "main thread : wait for homing\n";
state.wait_for(motion_state_v::homing, 30s); // first wait for background process to start homing
std::cout << "main thread : wait for running\n";
state.wait_for(motion_state_v::running, 30s); // then wait for homed
std::cout << "main thread : done\n";
return 0;
}