17 SignaledTask
Hosts a thread with explicit Start/Stop functions. Calls to Signal() cause the given task
to be executed by the worker thread. Note however that by design there is no requirement
that there will be one execution of the task for each call to Signal() (i.e. that the calls
will be paired). Rather, the implementation only records the signaled state with a
boolean, not a counter for the number of calls to Signal().
If while a task is executing there are multiple calls to Signal() then the task will only be made
to execute one more time by those calls to Signal().
SignaledTask.h
// SignaledTask.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2013
#pragma once
#ifndef Ceda_cxThread_SignaledTask_H
#define Ceda_cxThread_SignaledTask_H
#include "cxThread.h"
#include "AutoResetEvent.h"
#include "ThreadName.h"
#include <thread>
#include <functional>
#include <atomic>
#ifdef _MSC_VER
// struct 'X' needs to have dll-interface to be used by clients of class 'Y'
#pragma warning(disable:4251)
#endif
namespace ceda
{
class cxThread_API SignaledTask
{
public:
SignaledTask();
~SignaledTask();
void Start(const char* threadName, std::function<void()> task);
void Stop();
void Signal();
// A task can call this to poll whether it should complete as soon as possible
bool Abort() const { return !started_; }
private:
xstring threadName_;
std::thread thread_;
volatile bool started_;
// Event used to wake up the thread from its dormant state. This can be for two reasons
// 1. The thread is being stopped
// 2. It is time to perform run the task
AutoResetEvent wakeThreadEvent_;
// Task to be executed when Signal() is called
std::function<void()> task_;
};
} // namespace ceda
#endif // include guard
SignaledTask.cpp
// SignaledTask.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2013
#include "SignaledTask.h"
namespace ceda
{
SignaledTask::SignaledTask() : started_(false) {}
SignaledTask::~SignaledTask()
{
cxAssert(!started_);
}
void SignaledTask::Start(const char* threadName, std::function<void ()> task)
{
threadName_ = threadName;
task_ = task;
cxAssert(!started_);
started_ = true;
thread_ = std::thread(
[this]
{
SetThreadName(threadName_.c_str());
while(1)
{
wakeThreadEvent_.Wait();
if (!started_) return;
task_();
}
});
}
void SignaledTask::Stop()
{
cxAssert(started_);
started_ = false;
wakeThreadEvent_.Signal();
thread_.join();
}
void SignaledTask::Signal()
{
cxAssert(started_);
wakeThreadEvent_.Signal();
}
} // namespace ceda
SignaledTaskTests.cpp in txThread
Even though the test calls Signal() six times, the task is only called three times:
Generated output:
UnitTestSignaledTask
task() called
task() called
task() called
// SignaledTaskTests.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2013
#include "Ceda/cxThread/SignaledTask.h"
#include "Ceda/cxUtils/Tracer.h"
#include "Ceda/cxUtils/HPTime.h"
void UnitTestSignaledTask()
{
Tracer() << "UnitTestSignaledTask\n";
ceda::SignaledTask st;
st.Start("UnitTestSignaledTask",
[]()
{
Tracer() << " task() called\n";
});
st.Signal();
st.Signal();
st.Signal();
Sleep(10);
st.Signal();
Sleep(10);
st.Signal();
st.Signal();
Sleep(10);
st.Stop();
}