File: ThreadRunner.cpp

package info (click to toggle)
yade 2026.1.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 34,448 kB
  • sloc: cpp: 97,645; python: 52,173; sh: 677; makefile: 162
file content (97 lines) | stat: -rw-r--r-- 3,032 bytes parent folder | download | duplicates (2)
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