#include "TApplication.h" #include "TObject.h" #include "TH1.h" #include "TMath.h" #include "TCanvas.h" #include "TRandom.h" #include "TThread.h" /* ** Module name : threads ** ** Description : ** This file implements four functions, which shall perform some ** actions on objects like histograms and a canvas. */ // a global canvas for the drawing of histograms TCanvas *c1; // a pad for the histogram, will be used by thread mhs TPad *pad1; // a pad for the histogram, will be used by thread mhs2 TPad *pad2; // a global histogram object, which will be accessed both by mhs and mhs1 TH1F *total0; // thread function (filling histogram main and drawing total0 on pad1) void *mhs(void *) { TThread::Printf("Start of mhs"); // change to the canvas and draw its correspondig pad 1 c1->cd(); c1->SetGrid(); pad1->Draw(); // creating a histogram is explicitly locked by a global mutex TThread::Lock(); TH1F *main = new TH1F("main","Main contributor",100,-4,4); TThread::UnLock(); // other operations needn't be locked total0->Sumw2(); total0->SetMarkerStyle(21); total0->SetMarkerSize(0.7); main->SetFillColor(16); // Fill histogram main randomly gRandom->SetSeed(); const Int_t kUPDATE = 100; Float_t xmain; // run for a certain amount of events or //for ( Int_t i=0; i<=100000; i++) { // run forever for ( Int_t i=0; ; i++) { xmain = gRandom->Gaus(-1,1.5); // filling of a histogram is locked to avoid data loss TThread::Lock(); main->Fill(xmain); total0->Fill(xmain); TThread::UnLock(); // drawing of the histogram is locked automatically by ROOT if (!(i%kUPDATE)) { if (i == kUPDATE) { pad1->cd(); total0->Draw("e1p"); } pad1->Modified(); pad1->Update(); c1->Modified(); c1->Update(); } // sleep for 1 ms: sleep not necessary, slows things only a bit down // because the threads are actually doing nothing, which is eventually // very fast ;-) TThread::Sleep(0, 1000000); } TThread::Printf("End of mhs\n"); c1->Modified(); c1->Update(); return 0; } // thread function (filling total0) void *mhs1(void *) { TThread::Printf("Start of mhs1"); // instantiation of objects has to be locked explicitly TThread::Lock(); TH1F *s1 = new TH1F("s1","This is the first signal",100,-4,4); TH1F *s2 = new TH1F("s2","This is the second signal",100,-4,4); TThread::UnLock(); s1->SetFillColor(42); s2->SetFillColor(46); // Fill histograms randomly gRandom->SetSeed(); Float_t xs1, xs2; //for ( Int_t i=0; i<=100000; i++) { for ( Int_t i=0; ; i++) { xs1 = gRandom->Gaus(-0.5,0.5); xs2 = gRandom->Gaus(1,0.3); // locking avoids data loss TThread::Lock(); s1->Fill(xs1,0.3); s2->Fill(xs2,0.2); total0->Fill(xs1,0.3); total0->Fill(xs2,0.2); TThread::UnLock(); // sleep for 6 ms: not necessary (see above) TThread::Sleep(0, 6000000); } TThread::Printf("End of mhs1\n"); // wo is last draws the histogram a last time pad1->cd(); total0->Draw("e1p"); c1->Modified(); c1->Update(); return 0; } // thread function: plays with its own histograms, draw on canvas in pad2 void *mhs2(void *) { TThread::Printf("Start of mhs2"); c1->cd(); pad2->Draw(); // Create some histograms: explicitly locked. TThread::Lock(); TH1F *total = new TH1F("total2","This is the total distribution",100,-4,4); TH1F *main = new TH1F("main2","Main contributor",100,-4,4); TH1F *s1 = new TH1F("s12","This is the first signal",100,-4,4); TH1F *s2 = new TH1F("s22","This is the second signal",100,-4,4); TThread::UnLock(); total->Sumw2(); total->SetMarkerStyle(21); total->SetMarkerSize(0.7); main->SetFillColor(16); s1->SetFillColor(42); s2->SetFillColor(46); // Fill histograms randomly gRandom->SetSeed(); const Int_t kUPDATE = 100; Float_t xs1, xs2, xmain; // for ( Int_t i=0; i<=100000; i++) { for ( Int_t i=0; ; i++) { xmain = gRandom->Gaus(-1,1.5); xs1 = gRandom->Gaus(-0.5,0.5); xs2 = gRandom->Gaus(1,0.3); // no locking here because nobody else uses these objects main->Fill(xmain); s1->Fill(xs1,0.3); s2->Fill(xs2,0.2); total->Fill(xmain); total->Fill(xs1,0.3); total->Fill(xs2,0.2); if (!(i%kUPDATE)) { if (i == kUPDATE) { pad2->cd(); total->Draw("e1p"); } pad2->Modified(); pad2->Update(); c1->Modified(); c1->Update(); } // sleep for 1 ms: not necessary TThread::Sleep(0, 1000000); } TThread::Printf("End of mhs2\n"); c1->Modified(); c1->Update(); return 0; } // thread to run Ps(): perform every 5 seconds a TThread::Ps() void *top(void *) { TThread::Printf("Start of top"); for (Int_t i = 0; ;i++) { TThread::Ps(); TThread::Sleep(5); } TThread::Printf("End of top"); return 0; } int main(int argc, char **argv) { TApplication theApp("h1Thread", &argc, argv); // a global canvas for the drawing of histograms c1 = new TCanvas("c1","The HSUM example",800,400); // a pad for the histogram, will be used by thread mhs pad1 = new TPad("pad1","This is pad1",0.02,0.02,0.48,0.98,33); // a pad for the histogram, will be used by thread mhs2 pad2 = new TPad("pad2","This is pad2",0.52,0.02,0.98,0.98,33); // a global histogram object, which will be accessed both by mhs and mhs1 total0 = new TH1F("total","This is the total distribution",100,-4,4); // create the TThread instances TThread *th1 = new TThread("th1",mhs); TThread *th2 = new TThread("th2",mhs2); TThread *th3 = new TThread("th3",mhs1); // top thread TThread *thp = new TThread("top",top); th1->Run(); th2->Run(); th3->Run(); thp->Run(); printf("*** Exit the program by selecting Quit from the File menu ***\n"); theApp.Run(kTRUE); th1->SetCancelAsynchronous(); th2->SetCancelAsynchronous(); th3->SetCancelAsynchronous(); thp->SetCancelAsynchronous(); th1->Kill(); th2->Kill(); th3->Kill(); thp->Kill(); printf("The END...\n"); return 0; }