1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
/*************************************************************************
* Copyright (C) 2006 by Janek Kozicki *
* cosurgi@berlios.de *
* *
* This program is free software; it is licensed under the terms of the *
* GNU General Public License v2 or later. See file LICENSE for details. *
*************************************************************************/
#include "ThreadRunner.hpp"
#include "ThreadWorker.hpp"
#include <lib/base/Logging.hpp>
#include <boost/bind/bind.hpp>
#include <boost/function.hpp>
#include <boost/thread/thread.hpp>
namespace yade { // Cannot have #include directive inside.
CREATE_LOGGER(ThreadRunner);
void ThreadRunner::run()
{
// this is the body of execution of separate thread
const std::lock_guard<std::mutex> lock(m_runmutex);
try {
workerThrew = false;
while (looping()) {
call();
if (m_thread_worker->shouldTerminate()) {
stop();
return;
}
}
} catch (std::exception& e) {
LOG_FATAL("Exception occured: " << std::endl << e.what());
workerException = std::runtime_error(e.what());
workerThrew = true;
stop();
return;
}
}
void ThreadRunner::call()
{
// this is the body of execution of separate thread
//
// FIXME - if several threads are blocked here and waiting, and the
// destructor is called we get a crash. This happens if some other
// thread is calling spawnSingleAction in a loop (instead of calling
// start() and stop() as it normally should). This is currently the
// case of SimulationController with synchronization turned on.
//
// the solution is to use a counter (perhaps recursive_mutex?) which
// will count the number of threads in the queue, and only after they
// all finish execution the destructor will be able to finish its work
//
const std::lock_guard<std::mutex> lock(m_callmutex);
m_thread_worker->setTerminate(false);
m_thread_worker->callSingleAction();
}
// TODO for the future.
//bool ThreadRunner::permissionToDestroy() const
//{
// // FIXME: think about locking to prevent next ThreadRunner::call() from starting, while this is being destroyed.
// return m_thread_worker->done();
//}
void ThreadRunner::spawnSingleAction()
{
if (m_looping) return;
const std::lock_guard<std::mutex> calllock(m_callmutex);
boost::function0<void> call(boost::bind(&ThreadRunner::call, this));
boost::thread th(call);
}
void ThreadRunner::start()
{
if (!m_looping.exchange(true)) {
boost::function0<void> run(boost::bind(&ThreadRunner::run, this));
boost::thread th(run);
}
}
void ThreadRunner::stop() { m_looping = false; }
bool ThreadRunner::looping() const { return m_looping; }
ThreadRunner::~ThreadRunner()
{
stop();
m_thread_worker->setTerminate(true);
const std::lock_guard<std::mutex> runlock(m_runmutex);
const std::lock_guard<std::mutex> calllock(m_callmutex);
}
} // namespace yade
|