Version: 9.16.0
AlternateThreadPT.cxx
Go to the documentation of this file.
1// Copyright (C) 2006-2026 CEA, EDF
2//
3// This library is free software; you can redistribute it and/or
4// modify it under the terms of the GNU Lesser General Public
5// License as published by the Free Software Foundation; either
6// version 2.1 of the License, or (at your option) any later version.
7//
8// This library is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// Lesser General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public
14// License along with this library; if not, write to the Free Software
15// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16//
17// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18//
19
20#include <iostream>
21#include <typeinfo>
22
23#include "AlternateThreadPT.hxx"
24
25//#define _DEVDEBUG_
26#include "YacsTrace.hxx"
27
28using namespace std;
29using namespace YACS::BASES;
30
31AlternateThreadPT::AlternateThreadPT()
32 : _threadStatus(UNEXISTING)
33{
34 YASSERT(pthread_cond_init(&_pingPongCond, NULL) == 0)
35 YASSERT(pthread_mutex_init(&_pingPongMutex, NULL) == 0)
36}
37
39{
40 try {
42 YASSERT(pthread_mutex_destroy(&_pingPongMutex) == 0)
43 YASSERT(pthread_cond_destroy(&_pingPongCond) == 0)
44 } catch (const exception & e) {
45 cerr << "Exception happened in AlternateThreadPT destructor: " << e.what() << endl;
46 } catch (...) {
47 cerr << "Unknown exception happened in AlternateThreadPT destructor." << endl;
48 }
49}
50
52{
53 // This method must not be called if a slave thread is running
55
56 YASSERT(pthread_mutex_lock(&_pingPongMutex) == 0)
57 DEBTRACE("Starting thread")
58 YASSERT(pthread_create(&_threadId, 0, runThread, this) == 0)
59 DEBTRACE("Master waiting for slave")
60 YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
61 DEBTRACE("Master running again")
62}
63
65{
66 // This method must not be called by the slave thread
67 YASSERT(_threadStatus == UNEXISTING || !pthread_equal(pthread_self(), _threadId))
68
69 switch (_threadStatus) {
70 case UNEXISTING:
71 return;
72 case READY_TO_JOIN:
73 break;
74 case NORMAL_CYCLE:
75 {
76 // First try to signal the slave thread to end properly
77 DEBTRACE("Master is trying to terminate slave by signaling error")
80
82 // Try to cancel the thread
83 cerr << "Warning: Slave thread in AlternateThread did not end properly. "
84 "Thread will be canceled." << endl;
85 YASSERT(pthread_cancel(_threadId) == 0)
86 YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
87
89 // If cancel failed, we can do nothing more, throw an exception
90 YASSERT(false);
91 }
92 }
93 break;
94 }
95 default:
96 YASSERT(false)
97 }
98
99 // Finally join the thread
100 YASSERT(pthread_mutex_unlock(&_pingPongMutex) == 0)
101 YASSERT(pthread_join(_threadId, NULL) == 0)
103 DEBTRACE("AlternateThread terminated")
104}
105
107{
108 YASSERT(!pthread_equal(pthread_self(), _threadId))
109 DEBTRACE("Master signaling slave and waiting");
111 DEBTRACE("Master running again");
112}
113
115{
116 YASSERT(pthread_equal(pthread_self(), _threadId))
117 DEBTRACE("Slave signaling master and waiting");
119 DEBTRACE("Slave running again");
120}
121
123{
125 YASSERT(pthread_cond_signal(&_pingPongCond) == 0)
126 YASSERT(pthread_cond_wait(&_pingPongCond, &_pingPongMutex) == 0)
127}
128
130{
132}
133
135{
136 return _threadStatus;
137}
138
139void * AlternateThreadPT::runThread(void * instance)
140{
141 try {
142 AlternateThreadPT * instanceCst = (AlternateThreadPT *)instance;
143 YASSERT(pthread_mutex_lock(&instanceCst->_pingPongMutex) == 0)
144 DEBTRACE("Slave thread is now running")
145 instanceCst->_threadStatus = NORMAL_CYCLE;
146 pthread_cleanup_push(threadCleanupFct, instance);
147 instanceCst->run();
148 pthread_cleanup_pop(1);
149 } catch (const exception & e) {
150 cerr << "Unrecoverable error: an exception was caught in AlternateThread "
151 "(exceptions should normally be caught before getting here). "
152 "Exception type is: " << typeid(e).name() << ", message is: " <<
153 e.what() << endl;
154 threadCleanupFct(instance);
155 }
156 // We can't catch (...) here because it causes problems with thread cancellation, at least
157 // with gcc 4.1.2 and older. With newer versions it should be possible to do something like
158 // catch (abi::__forced_unwind e) { throw; }. See
159 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28145 for details.
160 // The problem is that no exception should get out of the thread scope without being caught
161 // (otherwise the program aborts). So for now the user has to take care of catching all
162 // exceptions, but he cannot use catch (...).
163 return NULL;
164}
165
167{
168 // Beware of not throwing exceptions in this method
169 DEBTRACE("Cleaning up slave thread")
170 AlternateThreadPT * instanceCst = (AlternateThreadPT *)instance;
171 instanceCst->_threadStatus = READY_TO_JOIN;
172 pthread_cond_signal(&instanceCst->_pingPongCond);
173 pthread_mutex_unlock(&instanceCst->_pingPongMutex);
174}
#define YASSERT(val)
YASSERT macro is always defined, used like assert, but throw a YACS::Exception instead of abort.
Definition: YacsTrace.hxx:59
#define DEBTRACE(msg)
Definition: YacsTrace.hxx:31
This class provides a mechanism to run two threads alternately.
virtual void signalSlaveAndWait()
Block the master thread and release the slave thread.
bool isTerminationRequested() const
Return true if the master requested the slave thread termination.
virtual void run()=0
This method must be implemented in subclasses and will be run in the slave thread.
virtual void signalMasterAndWait()
Block the slave thread and release the master thread.
ThreadStatus getThreadStatus() const
Return the thread status.
void terminateSlaveThread()
Terminate the slave thread.
static void threadCleanupFct(void *instance)
void start()
Create and launch the slave thread.
static void * runThread(void *instance)