GSI Object Oriented Online Offline (Go4)  GO4-5.3.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 999 2013-07-25 11:58:59Z 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 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 // this does not work properly for ROOT versions < 5.17-04
208 // due to bug in static Delete() method (see root bug report 31085)
209 // TThread::Delete(fxThread);
210 // use workaround, later with root version ifdefs:
211  fxThread->Kill();
212  delete fxThread;
213 // note: this will skip the thread Cleanup(), but we do not use this feature in Go4
214 
216 //#ifndef WIN32
217 // // the following cleanup might fail on win32, better not do it...
218 // if(TThread::GetThread(fiThreadSelfID)!=0)
219 // {
220 // //std::cout <<"thread of "<<fiThreadSelfID<<" not yet deleted, do it now:" << std::endl;
221 // delete fxThread; // only delete thread if Cleanup method of TThread::Delete not yet invoked
222 // }
223 //#endif
224  fxThread=0;
225  fiThreadPID=0;
226  fiThreadSelfID=0;
227 
228  }
229  else
230  {
231  GO4TRACE((13,"TGo4Thread::Cancel() -- Error: TThread pointer is zero!",__LINE__, __FILE__));
232  TGo4Log::Debug(" Go4Thread ``%s'' Cancel -- Internal inconsistency error! ",GetName());
233  throw TGo4RuntimeException();
234  }
235  return kTRUE;
236  }
237  else
238  // no such thread...
239  {
240  return kFALSE;
241  }
242 }
243 
245 {
246  GO4TRACE((14,"TGo4Thread::ReCreate()",__LINE__, __FILE__));
247 
248  TThread* oldthread;
249  if(fbIsCreated)
250  // thread existing, then recreate possible
251 
252  {
253  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
254  TGo4Log::Debug(" Recreating Go4Thread ``%s'' -- old TThread %d (PID:%d) ",
255  GetName(), fiThreadSelfID, fiThreadPID);
256  //std::cout << "recreating thread "<<GetName()<< std::endl;
257  if(fxThread)
258  {
259  GO4TRACE((13,"TGo4Thread::ReCreate() -- recreating existing TThread",__LINE__, __FILE__));
260  Stop();// halt runnable
261  oldthread=fxThread; // remember old TThread
262  // first start new TThread of same Threadfunc and runnable:
263  fxThread= new TThread(GetName(),
264  (void(*) (void *)) &Threadfunc ,
265  (void*) this);
266 
267  // then kill the old TThread, so Threadfunc may ReCreate() itself
268  fbIsCreated=kFALSE;
269  if(fbIsWaiting)
270  {
271  fxCondition->Signal(); // unlock condition mutex before deleting it
272  // this will not start the runnable, fbIsRunning still false
273  //fbIsWaiting=kFALSE; // keep flag consistent with Threadfunc state..
274  }
275  TThread::Delete(oldthread);
276  //delete oldthread;
277  fbIsCreated=kTRUE;
278  fxThread->Run(); // does this work if thread recreates itself?
279  Start(); // start runnable in new TThread
280 
281  }
282  else
283  {
284  GO4TRACE((13,"TGo4Thread::ReCreate() -- Error: old TThread pointer is zero!",__LINE__, __FILE__));
285  TGo4Log::Debug(" Go4Thread ``%s'' ReCreate -- Internal inconsistency error! ",GetName());
286  //std::cout << "TGo4Thread "<<GetName()<<" ReCreate inconsistency error!"<< std::endl;
287  throw TGo4RuntimeException();
288  }
289  return kTRUE;
290  }
291  else //if(fbIsCreated)
292  // no old thread, then create new one
293  {
294  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
295  Create();
296  return kFALSE;
297  }
298 }
299 
301 {
302  GO4TRACE((12,"TGo4Thread::Start()",__LINE__, __FILE__));
303  if(!fbIsCreated)
304  // check if thread is up
305  {
306  // not yet created, then do so
307  GO4TRACE((11,"TGo4Thread::Start() -- creating new TThread",__LINE__, __FILE__));
308  Create();
309  }
310  else
311  {
312  // do nothing, thread already there
313  GO4TRACE((11,"TGo4Thread::Start() -- TThread already existing",__LINE__, __FILE__));
314  }
315  Bool_t old=fbIsRunning;
316  fbIsRunning=kTRUE;
317  fxCondition->Signal(); // wake up waiting threadfunction
318  return old; // old status of workfunc requested by thread list
319 }
320 
322 {
323  GO4TRACE((12,"TGo4Thread::Stop()",__LINE__, __FILE__));
324  Bool_t old=fbIsRunning;
325  fbIsRunning=kFALSE;
326  return old; // old status of workfunc requested by thread list
327 }
328 
329 void TGo4Thread::Sleep (UInt_t millisecs)
330 {
331  GO4TRACE((12,"TGo4Thread::Sleep()",__LINE__, __FILE__));
332  gSystem->Sleep(millisecs);
333  TThread::CancelPoint();
334 }
335 
337 {
338  fiThreadSelfID = TThread::SelfId();
339 }
340 
342 {
343  fiThreadPID = gSystem->GetPid();
344 }
Bool_t IsRunning() const
Definition: TGo4Thread.h:83
virtual void ThreadCatch(TGo4Exception &ex)
Bool_t Stop()
Definition: TGo4Thread.cxx:321
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:329
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:341
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:244
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:336
Bool_t Start()
Definition: TGo4Thread.cxx:300
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