GSI Object Oriented Online Offline (Go4)  GO4-5.3.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4Thread.cxx
Go to the documentation of this file.
1 // $Id: TGo4Thread.cxx 2162 2018-10-10 14:16:24Z adamczew $
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum für Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 #include "TGo4Thread.h"
15 
16 #include "TThread.h"
17 #include "TSystem.h"
18 #include "TCondition.h"
19 
20 #include "TGo4Runnable.h"
21 #include "TGo4Log.h"
22 #include "TGo4LockGuard.h"
23 #include "Go4Exceptions.h"
24 
26  :TNamed(right)
27 {
28  GO4TRACE((14,"TGo4Thread::TGo4Thread() copy constructor",__LINE__, __FILE__));
29  fxRunnable = right.fxRunnable;
30  fbIsInternal = right.fbIsInternal;
31  fxCondition = new TCondition();
32 }
33 
34 TGo4Thread::TGo4Thread (const char* name, TGo4Runnable* runnable, Bool_t internal)
35  :TNamed(name,"This is a TGo4Thread"),
36  fbIsCreated(kFALSE),
37  fbIsRunning(kFALSE),
38  fiThreadPID(0),
39  fiThreadSelfID(0),
40  fbIsWaiting(kFALSE),
41  fxThread(0)
42 {
43  GO4TRACE((14,"TGo4Thread::TGo4Thread(const char*, TGo4Runnable*, Bool_t) constructor",__LINE__, __FILE__));
44 
45  TGo4Log::Debug(" New Go4Thread ``%s'' created ",name);
46  fxRunnable = runnable;
47  fbIsInternal = internal;
48  fxCondition = new TCondition();
49  fxRunnable->SetThread(this);
50 }
51 
52 
54 {
55  GO4TRACE((14,"TGo4Thread::~TGo4Thread() destructor",__LINE__, __FILE__));
56 
57  Stop();
58  Cancel();
59  delete fxCondition;
60  if(fbIsInternal)
61  {
62  GO4TRACE((14,"TGo4Thread::~TGo4Thread() internal mode",__LINE__, __FILE__));
63  TGo4Log::Debug(" Go4Thread ``%s'' deleting runnable ``%s'' ",
64  GetName(),fxRunnable->GetName());
65  delete fxRunnable; // internal mode: go4thread responsible for runnable
66  }
67  else
68  {
69  GO4TRACE((14,"TGo4Thread::~TGo4Thread() non internal mode",__LINE__, __FILE__));
70  // do nothing
71  }
72 
73 }
74 
75 void TGo4Thread::Threadfunc (void* arg)
76 {
77  GO4TRACE((2,"TGo4Thread::Threadfunc(void*)",__LINE__, __FILE__));
78  TGo4Thread* go4th= (TGo4Thread*) arg; // we need reference to calling class instance
79  TGo4Runnable* runnable = go4th->GetRunnable();
80 
81  // this is the function running as pthread...
82  // initializations:
83  go4th->SetPID();
84  go4th->SetSelfID();
85 // fiThreadPID=gSystem->GetPid(); // set ids
86 // fiThreadSelfID=TThread::SelfId();
87  TGo4Log::Debug(" TThread %d (PID:%d) of Go4Thread ``%s'' started... \n",
88  go4th->GetSelfID(), go4th->GetPID(), go4th->GetName());
89 
90 for(;;) // loop keeps thread alive after exception has occured...
91  {
92  try
93  {
94  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) try block",__LINE__, __FILE__));
95  while(1)
96  {
97  TThread::CancelPoint();
98  if( !(go4th->IsRunning()) )
99  {
100  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) waiting mode",__LINE__, __FILE__));
101  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) waiting...\n",
102  go4th->GetName(), go4th->GetPID());
103  go4th->SetWaiting(kTRUE);
104  go4th->GetCondition()->Wait(); //wait for funcrun condition
105  go4th->SetWaiting(kFALSE);
106  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) running...\n",
107  go4th->GetName(), go4th->GetPID() );
108  }
109  else
110  {
111  // Do Nothing, just continue
112  }
113 
114  if(go4th->IsCreated())
115  // normal mode: enter runnable
116  {
117  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) entering running mode",__LINE__, __FILE__));
118  // call runnable prerun method before running:
119  runnable->PreRun((void*) 0); // we are runnable's friend, can call protected method...
120  while(go4th->IsRunning())
121  {
122  TThread::CancelPoint();
123  runnable->Run((void*) 0); // we are runnable's friend, can call protected method...
124  }
125  // call runnable postrun method before stopping
126  runnable->PostRun((void*) 0); // we are runnable's friend, can call protected method...
127 
128  }
129  else
130  // aborting mode after condition release: loop cancel point
131  {
132  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) entering Cancel loop",__LINE__, __FILE__));
133  TGo4Log::Debug(" Go4Thread ``%s'' entering Cancel loop\n ", go4th->GetName());
134  while(!(go4th->IsCreated()))
135  {
136  {
137  #ifdef WIN32
138  return; // cancel point does not work on windows; escape to root thread framework...
139  #endif
140  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) in Cancel loop",__LINE__, __FILE__));
141  Sleep(500);
142  TThread::CancelPoint();
143  }
144  }
145  }
146  } // while(1)
147  }// try
148  catch(TGo4Exception& ex)
149  {
150  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) Go4Exception Catch",__LINE__, __FILE__));
151  runnable->ThreadCatch(ex);
152  TThread::CancelPoint();
153  }
154 
155  catch(...)
156  {
157  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) Unexpected Catch",__LINE__, __FILE__));
158  //runnable->UnexpectedCatch(); // do not handle alien exceptions!
159  TThread::CancelPoint();
160  throw; // otherwise, we have trouble with newer pthread
161  // implementations that use one pid for all threads, e.g. Fedora2
162  }
163 
164  } // for(;;) loop keeps thread alive
165 }
166 
168 {
169  GO4TRACE((14,"TGo4Thread::Create()",__LINE__, __FILE__));
170  if(!fbIsCreated)
171  // thread not existing, create it
172  {
173  fxThread= new TThread(GetName(),
174  (void(*) (void *)) &Threadfunc ,
175  (void*) this);
176  fxThread->Run();
177  fbIsCreated=kTRUE;
178  return kTRUE;
179  }
180  else
181  // thread instance already there...
182  {
183  return kFALSE;
184  }
185 }
186 
188 {
189  GO4TRACE((14,"TGo4Thread::Cancel()",__LINE__, __FILE__));
190 
191  if(fbIsCreated)
192  // thread existing, then cancel
193  {
194  TGo4Log::Debug(" Go4Thread ``%s'' -- Canceling TThread %d (PID:%d) ",
195  GetName(), fiThreadSelfID, fiThreadPID);
196  //std::cout << "canceling thread "<<fiThreadSelfID<< std::endl;
197  if(fxThread)
198  {
199  GO4TRACE((13,"TGo4Thread::Cancel() -- canceling existing TThread",__LINE__, __FILE__));
200  fbIsCreated=kFALSE;
201  fbIsRunning=kTRUE; // these settings let Threadfunc enter Cancel loop
202  fxCondition->Signal(); // unlock condition mutex before deleting it
203  Sleep(500); // waitstate for Threadfunc to enter cancel loop after condition
204 
205 
206 
207  // JAM2018 bugfix for crashes with ROOT 6 concerning Thread CleanUpPop
208 #if ROOT_VERSION_CODE > ROOT_VERSION(6,0,0)
209  TThread::Delete(fxThread);
210 #else
211 // this does not work properly for ROOT versions < 5.17-04
212 // due to bug in static Delete() method (see root bug report 31085)
213 // TThread::Delete(fxThread);
214  fxThread->Kill();
215  delete fxThread;
216 // note: this will skip the thread Cleanup(), but we do not use this feature in Go4
217 #endif
218 
219 
220 
221 
223 //#ifndef WIN32
224 // // the following cleanup might fail on win32, better not do it...
225 // if(TThread::GetThread(fiThreadSelfID)!=0)
226 // {
227 // //std::cout <<"thread of "<<fiThreadSelfID<<" not yet deleted, do it now:" << std::endl;
228 // delete fxThread; // only delete thread if Cleanup method of TThread::Delete not yet invoked
229 // }
230 //#endif
231  fxThread=0;
232  fiThreadPID=0;
233  fiThreadSelfID=0;
234 
235  }
236  else
237  {
238  GO4TRACE((13,"TGo4Thread::Cancel() -- Error: TThread pointer is zero!",__LINE__, __FILE__));
239  TGo4Log::Debug(" Go4Thread ``%s'' Cancel -- Internal inconsistency error! ",GetName());
240  throw TGo4RuntimeException();
241  }
242  return kTRUE;
243  }
244  else
245  // no such thread...
246  {
247  return kFALSE;
248  }
249 }
250 
252 {
253  GO4TRACE((14,"TGo4Thread::ReCreate()",__LINE__, __FILE__));
254 
255  TThread* oldthread;
256  if(fbIsCreated)
257  // thread existing, then recreate possible
258 
259  {
260  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
261  TGo4Log::Debug(" Recreating Go4Thread ``%s'' -- old TThread %d (PID:%d) ",
262  GetName(), fiThreadSelfID, fiThreadPID);
263  //std::cout << "recreating thread "<<GetName()<< std::endl;
264  if(fxThread)
265  {
266  GO4TRACE((13,"TGo4Thread::ReCreate() -- recreating existing TThread",__LINE__, __FILE__));
267  Stop();// halt runnable
268  oldthread=fxThread; // remember old TThread
269  // first start new TThread of same Threadfunc and runnable:
270  fxThread= new TThread(GetName(),
271  (void(*) (void *)) &Threadfunc ,
272  (void*) this);
273 
274  // then kill the old TThread, so Threadfunc may ReCreate() itself
275  fbIsCreated=kFALSE;
276  if(fbIsWaiting)
277  {
278  fxCondition->Signal(); // unlock condition mutex before deleting it
279  // this will not start the runnable, fbIsRunning still false
280  //fbIsWaiting=kFALSE; // keep flag consistent with Threadfunc state..
281  }
282  TThread::Delete(oldthread);
283  //delete oldthread;
284  fbIsCreated=kTRUE;
285  fxThread->Run(); // does this work if thread recreates itself?
286  Start(); // start runnable in new TThread
287 
288  }
289  else
290  {
291  GO4TRACE((13,"TGo4Thread::ReCreate() -- Error: old TThread pointer is zero!",__LINE__, __FILE__));
292  TGo4Log::Debug(" Go4Thread ``%s'' ReCreate -- Internal inconsistency error! ",GetName());
293  //std::cout << "TGo4Thread "<<GetName()<<" ReCreate inconsistency error!"<< std::endl;
294  throw TGo4RuntimeException();
295  }
296  return kTRUE;
297  }
298  else //if(fbIsCreated)
299  // no old thread, then create new one
300  {
301  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
302  Create();
303  return kFALSE;
304  }
305 }
306 
308 {
309  GO4TRACE((12,"TGo4Thread::Start()",__LINE__, __FILE__));
310  if(!fbIsCreated)
311  // check if thread is up
312  {
313  // not yet created, then do so
314  GO4TRACE((11,"TGo4Thread::Start() -- creating new TThread",__LINE__, __FILE__));
315  Create();
316  }
317  else
318  {
319  // do nothing, thread already there
320  GO4TRACE((11,"TGo4Thread::Start() -- TThread already existing",__LINE__, __FILE__));
321  }
322  Bool_t old=fbIsRunning;
323  fbIsRunning=kTRUE;
324  fxCondition->Signal(); // wake up waiting threadfunction
325  return old; // old status of workfunc requested by thread list
326 }
327 
329 {
330  GO4TRACE((12,"TGo4Thread::Stop()",__LINE__, __FILE__));
331  Bool_t old=fbIsRunning;
332  fbIsRunning=kFALSE;
333  return old; // old status of workfunc requested by thread list
334 }
335 
336 void TGo4Thread::Sleep (UInt_t millisecs)
337 {
338  GO4TRACE((12,"TGo4Thread::Sleep()",__LINE__, __FILE__));
339  gSystem->Sleep(millisecs);
340  TThread::CancelPoint();
341 }
342 
344 {
345  fiThreadSelfID = TThread::SelfId();
346 }
347 
349 {
350  fiThreadPID = gSystem->GetPid();
351 }
Bool_t IsRunning() const
Definition: TGo4Thread.h:83
virtual void ThreadCatch(TGo4Exception &ex)
Bool_t Stop()
Definition: TGo4Thread.cxx:328
void SetWaiting(Bool_t mode=kTRUE)
Definition: TGo4Thread.h:105
Bool_t Cancel()
Definition: TGo4Thread.cxx:187
static void Sleep(UInt_t millisecs)
Definition: TGo4Thread.cxx:336
static void Threadfunc(void *arg)
Definition: TGo4Thread.cxx:75
Bool_t IsCreated() const
Definition: TGo4Thread.h:80
TThread * fxThread
Definition: TGo4Thread.h:138
TCondition * fxCondition
Definition: TGo4Thread.h:140
virtual Int_t PreRun(void *ptr)
void SetThread(TGo4Thread *gthread)
Definition: TGo4Runnable.h:43
Long_t GetSelfID() const
Definition: TGo4Thread.h:73
virtual Int_t Run(void *ptr)=0
void SetPID()
Definition: TGo4Thread.cxx:348
TGo4Runnable * GetRunnable() const
Definition: TGo4Thread.h:97
virtual Int_t PostRun(void *ptr)
Long_t fiThreadSelfID
Definition: TGo4Thread.h:124
virtual ~TGo4Thread()
Definition: TGo4Thread.cxx:53
TGo4Runnable * fxRunnable
Definition: TGo4Thread.h:136
Int_t fiThreadPID
Definition: TGo4Thread.h:121
Bool_t fbIsRunning
Definition: TGo4Thread.h:118
Bool_t ReCreate()
Definition: TGo4Thread.cxx:251
Bool_t fbIsInternal
Definition: TGo4Thread.h:112
Bool_t Create()
Definition: TGo4Thread.cxx:167
Bool_t fbIsCreated
Definition: TGo4Thread.h:115
#define GO4TRACE(X)
Definition: TGo4Log.h:26
void SetSelfID()
Definition: TGo4Thread.cxx:343
Bool_t Start()
Definition: TGo4Thread.cxx:307
Bool_t fbIsWaiting
Definition: TGo4Thread.h:127
Int_t GetPID() const
Definition: TGo4Thread.h:70
TCondition * GetCondition() const
Definition: TGo4Thread.h:99
static void Debug(const char *text,...)
Definition: TGo4Log.cxx:270