GSI Object Oriented Online Offline (Go4)  GO4-6.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4Thread.cxx
Go to the documentation of this file.
1 // $Id: TGo4Thread.cxx 3501 2022-01-21 17:00:34Z linev $
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 fuer 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 "Go4Exceptions.h"
23 
25  :TNamed(right)
26 {
27  GO4TRACE((14,"TGo4Thread::TGo4Thread() copy constructor",__LINE__, __FILE__));
28  fxRunnable = right.fxRunnable;
29  fbIsInternal = right.fbIsInternal;
30  fxCondition = new TCondition();
31 }
32 
33 TGo4Thread::TGo4Thread (const char* name, TGo4Runnable* runnable, Bool_t internal)
34  :TNamed(name,"This is a TGo4Thread"),
35  fbIsCreated(kFALSE),
36  fbIsRunning(kFALSE),
37  fiThreadPID(0),
38  fiThreadSelfID(0),
39  fbIsWaiting(kFALSE),
40  fxThread(0)
41 {
42  GO4TRACE((14,"TGo4Thread::TGo4Thread(const char*, TGo4Runnable*, Bool_t) constructor",__LINE__, __FILE__));
43 
44  TGo4Log::Debug(" New Go4Thread ``%s'' created ",name);
45  fxRunnable = runnable;
46  fbIsInternal = internal;
47  fxCondition = new TCondition();
48  fxRunnable->SetThread(this);
49 }
50 
51 
53 {
54  GO4TRACE((14,"TGo4Thread::~TGo4Thread() destructor",__LINE__, __FILE__));
55 
56  Stop();
57  Cancel();
58  delete fxCondition;
59  if(fbIsInternal)
60  {
61  GO4TRACE((14,"TGo4Thread::~TGo4Thread() internal mode",__LINE__, __FILE__));
62  TGo4Log::Debug(" Go4Thread ``%s'' deleting runnable ``%s'' ",
63  GetName(),fxRunnable->GetName());
64  delete fxRunnable; // internal mode: go4thread responsible for runnable
65  }
66  else
67  {
68  GO4TRACE((14,"TGo4Thread::~TGo4Thread() non internal mode",__LINE__, __FILE__));
69  // do nothing
70  }
71 
72 }
73 
74 void TGo4Thread::Threadfunc (void* arg)
75 {
76  GO4TRACE((2,"TGo4Thread::Threadfunc(void*)",__LINE__, __FILE__));
77  TGo4Thread* go4th= (TGo4Thread*) arg; // we need reference to calling class instance
78  TGo4Runnable* runnable = go4th->GetRunnable();
79 
80  // this is the function running as pthread...
81  // initializations:
82  go4th->SetPID();
83  go4th->SetSelfID();
84 // fiThreadPID=gSystem->GetPid(); // set ids
85 // fiThreadSelfID=TThread::SelfId();
86  TGo4Log::Debug(" TThread %d (PID:%d) of Go4Thread ``%s'' started... \n",
87  go4th->GetSelfID(), go4th->GetPID(), go4th->GetName());
88 
89 for(;;) // loop keeps thread alive after exception has occured...
90  {
91  try
92  {
93  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) try block",__LINE__, __FILE__));
94  while(1)
95  {
96  TThread::CancelPoint();
97  if( !(go4th->IsRunning()) )
98  {
99  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) waiting mode",__LINE__, __FILE__));
100  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) waiting...\n",
101  go4th->GetName(), go4th->GetPID());
102  go4th->SetWaiting(kTRUE);
103  go4th->GetCondition()->Wait(); //wait for funcrun condition
104  go4th->SetWaiting(kFALSE);
105  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) running...\n",
106  go4th->GetName(), go4th->GetPID() );
107  }
108  else
109  {
110  // Do Nothing, just continue
111  }
112 
113  if(go4th->IsCreated())
114  // normal mode: enter runnable
115  {
116  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) entering running mode",__LINE__, __FILE__));
117  // call runnable prerun method before running:
118  runnable->PreRun((void*) 0); // we are runnable's friend, can call protected method...
119  while(go4th->IsRunning())
120  {
121  TThread::CancelPoint();
122  runnable->Run((void*) 0); // we are runnable's friend, can call protected method...
123  }
124  // call runnable postrun method before stopping
125  runnable->PostRun((void*) 0); // we are runnable's friend, can call protected method...
126 
127  }
128  else
129  // aborting mode after condition release: loop cancel point
130  {
131  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) entering Cancel loop",__LINE__, __FILE__));
132  TGo4Log::Debug(" Go4Thread ``%s'' entering Cancel loop\n ", go4th->GetName());
133  while(!(go4th->IsCreated()))
134  {
135  {
136  #ifdef WIN32
137  return; // cancel point does not work on windows; escape to root thread framework...
138  #else
139  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) in Cancel loop",__LINE__, __FILE__));
140  Sleep(500);
141  TThread::CancelPoint();
142  #endif
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:74
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:52
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:284