GSI Object Oriented Online Offline (Go4)  GO4-6.1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4Thread.cxx
Go to the documentation of this file.
1 // $Id: TGo4Thread.cxx 2758 2020-04-16 12:28:24Z 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  #endif
139  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) in Cancel loop",__LINE__, __FILE__));
140  Sleep(500);
141  TThread::CancelPoint();
142  }
143  }
144  }
145  } // while(1)
146  }// try
147  catch(TGo4Exception& ex)
148  {
149  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) Go4Exception Catch",__LINE__, __FILE__));
150  runnable->ThreadCatch(ex);
151  TThread::CancelPoint();
152  }
153 
154  catch(...)
155  {
156  GO4TRACE((1,"TGo4Thread::Threadfunc(void*) Unexpected Catch",__LINE__, __FILE__));
157  //runnable->UnexpectedCatch(); // do not handle alien exceptions!
158  TThread::CancelPoint();
159  throw; // otherwise, we have trouble with newer pthread
160  // implementations that use one pid for all threads, e.g. Fedora2
161  }
162 
163  } // for(;;) loop keeps thread alive
164 }
165 
167 {
168  GO4TRACE((14,"TGo4Thread::Create()",__LINE__, __FILE__));
169  if(!fbIsCreated)
170  // thread not existing, create it
171  {
172  fxThread= new TThread(GetName(),
173  (void(*) (void *)) &Threadfunc ,
174  (void*) this);
175  fxThread->Run();
176  fbIsCreated=kTRUE;
177  return kTRUE;
178  }
179  else
180  // thread instance already there...
181  {
182  return kFALSE;
183  }
184 }
185 
187 {
188  GO4TRACE((14,"TGo4Thread::Cancel()",__LINE__, __FILE__));
189 
190  if(fbIsCreated)
191  // thread existing, then cancel
192  {
193  TGo4Log::Debug(" Go4Thread ``%s'' -- Canceling TThread %d (PID:%d) ",
194  GetName(), fiThreadSelfID, fiThreadPID);
195  //std::cout << "canceling thread "<<fiThreadSelfID<< std::endl;
196  if(fxThread)
197  {
198  GO4TRACE((13,"TGo4Thread::Cancel() -- canceling existing TThread",__LINE__, __FILE__));
199  fbIsCreated=kFALSE;
200  fbIsRunning=kTRUE; // these settings let Threadfunc enter Cancel loop
201  fxCondition->Signal(); // unlock condition mutex before deleting it
202  Sleep(500); // waitstate for Threadfunc to enter cancel loop after condition
203 
204 
205 
206  // JAM2018 bugfix for crashes with ROOT 6 concerning Thread CleanUpPop
207 #if ROOT_VERSION_CODE > ROOT_VERSION(6,0,0)
208  TThread::Delete(fxThread);
209 #else
210 // this does not work properly for ROOT versions < 5.17-04
211 // due to bug in static Delete() method (see root bug report 31085)
212 // TThread::Delete(fxThread);
213  fxThread->Kill();
214  delete fxThread;
215 // note: this will skip the thread Cleanup(), but we do not use this feature in Go4
216 #endif
217 
218 
219 
220 
222 //#ifndef WIN32
223 // // the following cleanup might fail on win32, better not do it...
224 // if(TThread::GetThread(fiThreadSelfID)!=0)
225 // {
226 // //std::cout <<"thread of "<<fiThreadSelfID<<" not yet deleted, do it now:" << std::endl;
227 // delete fxThread; // only delete thread if Cleanup method of TThread::Delete not yet invoked
228 // }
229 //#endif
230  fxThread=0;
231  fiThreadPID=0;
232  fiThreadSelfID=0;
233 
234  }
235  else
236  {
237  GO4TRACE((13,"TGo4Thread::Cancel() -- Error: TThread pointer is zero!",__LINE__, __FILE__));
238  TGo4Log::Debug(" Go4Thread ``%s'' Cancel -- Internal inconsistency error! ",GetName());
239  throw TGo4RuntimeException();
240  }
241  return kTRUE;
242  }
243  else
244  // no such thread...
245  {
246  return kFALSE;
247  }
248 }
249 
251 {
252  GO4TRACE((14,"TGo4Thread::ReCreate()",__LINE__, __FILE__));
253 
254  TThread* oldthread;
255  if(fbIsCreated)
256  // thread existing, then recreate possible
257 
258  {
259  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
260  TGo4Log::Debug(" Recreating Go4Thread ``%s'' -- old TThread %d (PID:%d) ",
261  GetName(), fiThreadSelfID, fiThreadPID);
262  //std::cout << "recreating thread "<<GetName()<< std::endl;
263  if(fxThread)
264  {
265  GO4TRACE((13,"TGo4Thread::ReCreate() -- recreating existing TThread",__LINE__, __FILE__));
266  Stop();// halt runnable
267  oldthread=fxThread; // remember old TThread
268  // first start new TThread of same Threadfunc and runnable:
269  fxThread= new TThread(GetName(),
270  (void(*) (void *)) &Threadfunc ,
271  (void*) this);
272 
273  // then kill the old TThread, so Threadfunc may ReCreate() itself
274  fbIsCreated=kFALSE;
275  if(fbIsWaiting)
276  {
277  fxCondition->Signal(); // unlock condition mutex before deleting it
278  // this will not start the runnable, fbIsRunning still false
279  //fbIsWaiting=kFALSE; // keep flag consistent with Threadfunc state..
280  }
281  TThread::Delete(oldthread);
282  //delete oldthread;
283  fbIsCreated=kTRUE;
284  fxThread->Run(); // does this work if thread recreates itself?
285  Start(); // start runnable in new TThread
286 
287  }
288  else
289  {
290  GO4TRACE((13,"TGo4Thread::ReCreate() -- Error: old TThread pointer is zero!",__LINE__, __FILE__));
291  TGo4Log::Debug(" Go4Thread ``%s'' ReCreate -- Internal inconsistency error! ",GetName());
292  //std::cout << "TGo4Thread "<<GetName()<<" ReCreate inconsistency error!"<< std::endl;
293  throw TGo4RuntimeException();
294  }
295  return kTRUE;
296  }
297  else //if(fbIsCreated)
298  // no old thread, then create new one
299  {
300  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
301  Create();
302  return kFALSE;
303  }
304 }
305 
307 {
308  GO4TRACE((12,"TGo4Thread::Start()",__LINE__, __FILE__));
309  if(!fbIsCreated)
310  // check if thread is up
311  {
312  // not yet created, then do so
313  GO4TRACE((11,"TGo4Thread::Start() -- creating new TThread",__LINE__, __FILE__));
314  Create();
315  }
316  else
317  {
318  // do nothing, thread already there
319  GO4TRACE((11,"TGo4Thread::Start() -- TThread already existing",__LINE__, __FILE__));
320  }
321  Bool_t old=fbIsRunning;
322  fbIsRunning=kTRUE;
323  fxCondition->Signal(); // wake up waiting threadfunction
324  return old; // old status of workfunc requested by thread list
325 }
326 
328 {
329  GO4TRACE((12,"TGo4Thread::Stop()",__LINE__, __FILE__));
330  Bool_t old=fbIsRunning;
331  fbIsRunning=kFALSE;
332  return old; // old status of workfunc requested by thread list
333 }
334 
335 void TGo4Thread::Sleep (UInt_t millisecs)
336 {
337  GO4TRACE((12,"TGo4Thread::Sleep()",__LINE__, __FILE__));
338  gSystem->Sleep(millisecs);
339  TThread::CancelPoint();
340 }
341 
343 {
344  fiThreadSelfID = TThread::SelfId();
345 }
346 
348 {
349  fiThreadPID = gSystem->GetPid();
350 }
Bool_t IsRunning() const
Definition: TGo4Thread.h:83
virtual void ThreadCatch(TGo4Exception &ex)
Bool_t Stop()
Definition: TGo4Thread.cxx:327
void SetWaiting(Bool_t mode=kTRUE)
Definition: TGo4Thread.h:105
Bool_t Cancel()
Definition: TGo4Thread.cxx:186
static void Sleep(UInt_t millisecs)
Definition: TGo4Thread.cxx:335
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:347
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:250
Bool_t fbIsInternal
Definition: TGo4Thread.h:112
Bool_t Create()
Definition: TGo4Thread.cxx:166
Bool_t fbIsCreated
Definition: TGo4Thread.h:115
#define GO4TRACE(X)
Definition: TGo4Log.h:26
void SetSelfID()
Definition: TGo4Thread.cxx:342
Bool_t Start()
Definition: TGo4Thread.cxx:306
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:274