diff --git a/random/RandomGeneratorThread.cpp b/random/RandomGeneratorThread.cpp index 8c322f53..45fc74e4 100644 --- a/random/RandomGeneratorThread.cpp +++ b/random/RandomGeneratorThread.cpp @@ -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) { diff --git a/random/RandomGeneratorThread.h b/random/RandomGeneratorThread.h index 014550f9..895b3fc5 100644 --- a/random/RandomGeneratorThread.h +++ b/random/RandomGeneratorThread.h @@ -15,7 +15,7 @@ namespace cpputils { void start(); private: - void _loopIteration(); + bool _loopIteration(); Data _generateRandomData(size_t size); CryptoPP::AutoSeededRandomPool _randomGenerator; diff --git a/thread/LoopThread.cpp b/thread/LoopThread.cpp index e4ebc59a..6573d902 100644 --- a/thread/LoopThread.cpp +++ b/thread/LoopThread.cpp @@ -6,7 +6,7 @@ using boost::none; namespace cpputils { - LoopThread::LoopThread(function loopIteration): _loopIteration(loopIteration), _runningHandle(none) { + LoopThread::LoopThread(function loopIteration): _loopIteration(loopIteration), _runningHandle(none) { } LoopThread::~LoopThread() { diff --git a/thread/LoopThread.h b/thread/LoopThread.h index 7a167ee6..8f7bb5c5 100644 --- a/thread/LoopThread.h +++ b/thread/LoopThread.h @@ -13,13 +13,14 @@ namespace cpputils { // where the child class destructor already ran. class LoopThread final { public: - LoopThread(std::function loopIteration); + // The loopIteration callback returns true, if more iterations should be run, and false, if the thread should be terminated. + LoopThread(std::function loopIteration); ~LoopThread(); void start(); void stop(); private: - std::function _loopIteration; + std::function _loopIteration; boost::optional _runningHandle; }; } diff --git a/thread/ThreadSystem.cpp b/thread/ThreadSystem.cpp index f9dbbbaf..02b75b97 100644 --- a/thread/ThreadSystem.cpp +++ b/thread/ThreadSystem.cpp @@ -17,7 +17,7 @@ namespace cpputils { pthread_atfork(&ThreadSystem::_onBeforeFork, &ThreadSystem::_onAfterFork, &ThreadSystem::_onAfterFork); } - ThreadSystem::Handle ThreadSystem::start(function loopIteration) { + ThreadSystem::Handle ThreadSystem::start(function loopIteration) { boost::unique_lock 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 loopIteration) { + boost::thread ThreadSystem::_startThread(function loopIteration) { return boost::thread(std::bind(&ThreadSystem::_runThread, loopIteration)); } - void ThreadSystem::_runThread(function loopIteration) { + void ThreadSystem::_runThread(function 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(). } } diff --git a/thread/ThreadSystem.h b/thread/ThreadSystem.h index 30a9a6c8..b9a7b419 100644 --- a/thread/ThreadSystem.h +++ b/thread/ThreadSystem.h @@ -13,7 +13,7 @@ namespace cpputils { class ThreadSystem final { private: struct RunningThread { - std::function loopIteration; + std::function 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 loopIteration); + Handle start(std::function loopIteration); void stop(Handle handle); private: ThreadSystem(); - static void _runThread(std::function loopIteration); + static void _runThread(std::function 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 loopIteration); + boost::thread _startThread(std::function loopIteration); std::list _runningThreads; // std::list, because we give out iterators as handles boost::mutex _mutex;