源文件
InterruptibleSleep.h
#pragma once
#include <atomic>
#include <chrono>
#include <mutex>
namespace UtilityTools {
using namespace std;
class InterruptibleSleep
{
public:
bool start(const chrono::milliseconds & durInMS);
bool interrupt();
bool isSleeping() const;
bool isInterrupted() const;
private:
mutex m_alertGrd;
condition_variable m_alertSig;
atomic_bool m_bAlert{ false };
atomic_bool m_bSlping{ false };
};
}
InterruptibleSleep.cpp
#include "InterruptibleSleep.h"
using namespace std;
bool UtilityTools::InterruptibleSleep::start(const chrono::milliseconds & durInMS)
{
if (m_bSlping) return false;
unique_lock<mutex> lock(m_alertGrd);
m_bAlert = false;
m_bSlping = true;
m_alertSig.wait_for(lock, durInMS, [this]() { return m_bAlert.load(); });
m_bSlping = false;
return true;
}
bool UtilityTools::InterruptibleSleep::interrupt()
{
if (!m_bSlping) return false;
{
lock_guard<mutex> lock(m_alertGrd);
m_bAlert = true;
}
m_alertSig.notify_all();
return true;
}
bool UtilityTools::InterruptibleSleep::isSleeping() const {
return m_bSlping;
}
bool UtilityTools::InterruptibleSleep::isInterrupted() const {
return m_bAlert;
}
测试代码
#include "InterruptibleSleep.h"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <mutex>
#include <sstream>
using namespace std;
using namespace chrono_literals;
using namespace UtilityTools;
std::string currentTime()
{
using namespace std::chrono;
// get current time
auto now = system_clock::now();
// get number of milliseconds for the current second
// (remainder after division into seconds)
auto ms = duration_cast<milliseconds>(now.time_since_epoch()) % 1000;
// convert to time_t in order to convert to tm (broken time)
auto timer = system_clock::to_time_t(now);
// convert to broken time
#pragma warning(suppress : 4996)
tm bt = *localtime(&timer);
ostringstream oss;
oss << put_time(&bt, "%H:%M:%S"); // HH:MM:SS
oss << '.' << setfill('0') << setw(3) << ms.count();
return oss.str();
}
void printLog(const string & sLog)
{
static mutex mtx;
lock_guard<mutex> lg(mtx);
cout << "[" << currentTime() << "] " << sLog << endl;
}
atomic<bool> exitThread = false;
InterruptibleSleep iSlp;
void timerThread()
{
auto timeout = 100ms;
while (!exitThread) {
if (!iSlp.start(timeout)) {
cout << "Fail to sleep" << endl;
return;
} else { /* Do nothing */ }
if (exitThread) {
printLog("Timer thread exiting.");
return;
} else if (iSlp.isInterrupted()) {
printLog("Timer was interrupted due to alert.");
} else {
printLog("Timer achieved time-out.");
}
}
}
int main()
{
thread threadWait(&timerThread);
printLog("main(): Waiting 300ms...");
this_thread::sleep_for(300ms);
printLog("main(): Sim. interrupt.");
iSlp.interrupt();
printLog("main(): Waiting 50 ms...");
this_thread::sleep_for(50ms);
printLog("main(): Sim. interrupt.");
iSlp.interrupt();
printLog("main(): Waiting 50 ms...");
this_thread::sleep_for(50ms);
exitThread = true;
iSlp.interrupt();
threadWait.join();
printLog("Done.");
}
测试输出
[19:53:16.875] main(): Waiting 300ms...
[19:53:16.994] Timer achieved time-out.
[19:53:17.120] Timer achieved time-out.
[19:53:17.198] main(): Sim. interrupt.
[19:53:17.199] main(): Waiting 50 ms...
[19:53:17.200] Timer was interrupted due to alert.
[19:53:17.266] main(): Sim. interrupt.
[19:53:17.266] Timer was interrupted due to alert.
[19:53:17.267] main(): Waiting 50 ms...
[19:53:17.331] Timer thread exiting.
[19:53:17.332] Done.