Allow terminating LoopThreads from within
This commit is contained in:
parent
b92a87ab72
commit
9cea5d9090
@ -15,12 +15,13 @@ namespace cpputils {
|
||||
return _thread.start();
|
||||
}
|
||||
|
||||
void RandomGeneratorThread::_loopIteration() {
|
||||
bool RandomGeneratorThread::_loopIteration() {
|
||||
_buffer->waitUntilSizeIsLessThan(_minSize);
|
||||
size_t neededRandomDataSize = _maxSize - _buffer->size();
|
||||
ASSERT(_maxSize > _buffer->size(), "This could theoretically fail if another thread refilled the buffer. But we should be the only refilling thread.");
|
||||
Data randomData = _generateRandomData(neededRandomDataSize);
|
||||
_buffer->add(std::move(randomData));
|
||||
return true; // Run another iteration (don't terminate thread)
|
||||
}
|
||||
|
||||
Data RandomGeneratorThread::_generateRandomData(size_t size) {
|
||||
|
@ -15,7 +15,7 @@ namespace cpputils {
|
||||
void start();
|
||||
|
||||
private:
|
||||
void _loopIteration();
|
||||
bool _loopIteration();
|
||||
Data _generateRandomData(size_t size);
|
||||
|
||||
CryptoPP::AutoSeededRandomPool _randomGenerator;
|
||||
|
@ -6,7 +6,7 @@ using boost::none;
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
LoopThread::LoopThread(function<void()> loopIteration): _loopIteration(loopIteration), _runningHandle(none) {
|
||||
LoopThread::LoopThread(function<bool()> loopIteration): _loopIteration(loopIteration), _runningHandle(none) {
|
||||
}
|
||||
|
||||
LoopThread::~LoopThread() {
|
||||
|
@ -13,13 +13,14 @@ namespace cpputils {
|
||||
// where the child class destructor already ran.
|
||||
class LoopThread final {
|
||||
public:
|
||||
LoopThread(std::function<void()> loopIteration);
|
||||
// The loopIteration callback returns true, if more iterations should be run, and false, if the thread should be terminated.
|
||||
LoopThread(std::function<bool()> loopIteration);
|
||||
~LoopThread();
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::function<void()> _loopIteration;
|
||||
std::function<bool()> _loopIteration;
|
||||
boost::optional<ThreadSystem::Handle> _runningHandle;
|
||||
};
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace cpputils {
|
||||
pthread_atfork(&ThreadSystem::_onBeforeFork, &ThreadSystem::_onAfterFork, &ThreadSystem::_onAfterFork);
|
||||
}
|
||||
|
||||
ThreadSystem::Handle ThreadSystem::start(function<void()> loopIteration) {
|
||||
ThreadSystem::Handle ThreadSystem::start(function<bool()> loopIteration) {
|
||||
boost::unique_lock<boost::mutex> lock(_mutex);
|
||||
auto thread = _startThread(loopIteration);
|
||||
_runningThreads.push_back(RunningThread{loopIteration, std::move(thread)});
|
||||
@ -60,16 +60,18 @@ namespace cpputils {
|
||||
_mutex.unlock(); // Was locked in the before-fork handler
|
||||
}
|
||||
|
||||
boost::thread ThreadSystem::_startThread(function<void()> loopIteration) {
|
||||
boost::thread ThreadSystem::_startThread(function<bool()> loopIteration) {
|
||||
return boost::thread(std::bind(&ThreadSystem::_runThread, loopIteration));
|
||||
}
|
||||
|
||||
void ThreadSystem::_runThread(function<void()> loopIteration) {
|
||||
void ThreadSystem::_runThread(function<bool()> loopIteration) {
|
||||
try {
|
||||
while(true) {
|
||||
bool cont = true;
|
||||
while(cont) {
|
||||
boost::this_thread::interruption_point();
|
||||
loopIteration(); // This might also be interrupted.
|
||||
cont = loopIteration(); // This might also be interrupted.
|
||||
}
|
||||
//The thread is terminated gracefully.
|
||||
} catch (const boost::thread_interrupted &e) {
|
||||
//Do nothing, exit thread.
|
||||
} catch (const std::exception &e) {
|
||||
@ -77,5 +79,6 @@ namespace cpputils {
|
||||
} catch (...) {
|
||||
LOG(ERROR) << "LoopThread crashed";
|
||||
}
|
||||
//TODO We should remove the thread from _runningThreads here, not in stop().
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace cpputils {
|
||||
class ThreadSystem final {
|
||||
private:
|
||||
struct RunningThread {
|
||||
std::function<void()> loopIteration;
|
||||
std::function<bool()> loopIteration; // The loopIteration callback returns true, if more iterations should be run, and false, if the thread should be terminated.
|
||||
boost::thread thread; // boost::thread because we need it to be interruptible.
|
||||
};
|
||||
public:
|
||||
@ -21,20 +21,20 @@ namespace cpputils {
|
||||
|
||||
static ThreadSystem &singleton();
|
||||
|
||||
Handle start(std::function<void()> loopIteration);
|
||||
Handle start(std::function<bool()> loopIteration);
|
||||
void stop(Handle handle);
|
||||
|
||||
private:
|
||||
ThreadSystem();
|
||||
|
||||
static void _runThread(std::function<void()> loopIteration);
|
||||
static void _runThread(std::function<bool()> loopIteration);
|
||||
|
||||
static void _onBeforeFork();
|
||||
static void _onAfterFork();
|
||||
//TODO Rename to _doOnBeforeFork and _doAfterFork or similar, because they also handle locking _mutex for fork().
|
||||
void _stopAllThreadsForRestart();
|
||||
void _restartAllThreads();
|
||||
boost::thread _startThread(std::function<void()> loopIteration);
|
||||
boost::thread _startThread(std::function<bool()> loopIteration);
|
||||
|
||||
std::list<RunningThread> _runningThreads; // std::list, because we give out iterators as handles
|
||||
boost::mutex _mutex;
|
||||
|
Loading…
Reference in New Issue
Block a user