X-Git-Url: http://git.kpe.io/?p=ctsim.git;a=blobdiff_plain;f=src%2Fthreadrecon.cpp;h=dba08273bb2580683a8e31f2ce52866abe56e73c;hp=aa9a7bb9cdbfa419f0b5cf372c4999757dc5f2d5;hb=a97f1819c4f24321ba8d54a16f6534ee94404d26;hpb=0730f9f3adbf326b9d4bac754634399ad688efd1 diff --git a/src/threadrecon.cpp b/src/threadrecon.cpp index aa9a7bb..dba0827 100644 --- a/src/threadrecon.cpp +++ b/src/threadrecon.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2001 Kevin Rosenberg ** -** $Id: threadrecon.cpp,v 1.1 2001/02/22 11:05:38 kevin Exp $ +** $Id: threadrecon.cpp,v 1.13 2001/02/25 19:24:01 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -36,256 +36,241 @@ #include "docs.h" #include "views.h" #include "threadrecon.h" +#include "backgroundmgr.h" +#include "backgroundsupr.h" #if defined(HAVE_CONFIG_H) #include "config.h" #endif -IMPLEMENT_DYNAMIC_CLASS(ThreadedReconstructor, wxEvtHandler) -BEGIN_EVENT_TABLE(ThreadedReconstructor, wxEvtHandler) -EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ThreadedReconstructor::OnThreadEvent) -END_EVENT_TABLE() +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorSupervisorThread -- Thread for Background Supervisor +// +///////////////////////////////////////////////////////////////////// -enum { - RTHREAD_UNIT_COMPLETE = -1, - RTHREAD_THREAD_DONE = -2, - RTHREAD_THREAD_CANCELLED = -3, -}; - -ThreadedReconstructor::ThreadedReconstructor (ProjectionFileView* pProjView, - int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, - int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, +ReconstructorSupervisorThread::ReconstructorSupervisorThread (ProjectionFileView* pProjView, int iNX, int iNY, + const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad, + const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, const char* pszBackprojectName, const char* const pszLabel) - : m_pProjView(pProjView), m_pDialogProgress(NULL), m_bFail(false), m_iNumThreads(0), m_iImageNX(iImageNX), - m_iImageNY(iImageNY), m_strLabel(pszLabel), m_pTimer(NULL), m_bCancelled(false), m_bCancelling(false), - m_bDone(false), wxEvtHandler() +: m_pProjView(pProjView), m_iNX(iNX), m_iNY(iNY), m_strFilterName(pszFilterName), m_dFilterParam(dFilterParam), + m_strFilterMethod(pszFilterMethod), m_iZeropad(iZeropad), m_strFilterGenerationName(pszFilterGenerationName), + m_strInterpName(pszInterpName), m_iInterpParam(iInterpParam), m_strBackprojectName(pszBackprojectName), m_strLabel(pszLabel), + SupervisorThread() { - m_iNumThreads = theApp->getNumberCPU(); -// ++m_iNumThreads; - m_iTotalViews = m_pProjView->GetDocument()->getProjections().nView(); - int iBaseViews = m_iTotalViews / m_iNumThreads; - int iExtraViews = m_iTotalViews % m_iNumThreads; - - m_vecpChildImageFile.reserve (m_iNumThreads); - m_vecpReconstructor.reserve (m_iNumThreads); - m_vecpThread.reserve (m_iNumThreads); - - for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) { - m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY); - m_vecpReconstructor[iProc] = new Reconstructor (m_pProjView->GetDocument()->getProjections(), *m_vecpChildImageFile[iProc], - pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName, - pszInterpName, iInterpParam, pszBackprojectName, Trace::TRACE_NONE); - - int iStartView = iProc * iBaseViews; - int iNumViews = iBaseViews; - if (iProc < iExtraViews) - ++iNumViews; - m_vecpThread[iProc] = new ReconstructionThread (this, m_vecpReconstructor[iProc], iProc, iStartView, iNumViews); - if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) { - m_bFail = true; - break; - } - } - - m_pProjView->GetDocument()->addReconstructor (this); - // m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE); } - -bool -ThreadedReconstructor::start() +wxThread::ExitCode +ReconstructorSupervisorThread::Entry() { - if (m_bFail) - return false; - - // starting all threads - m_iRunning = m_iNumThreads; - m_iViewsDone = 0; - m_pTimer = new Timer; -// theApp->addBackgroundTask (this, m_iTotalViews); - - int i; - for (i = 0; i < m_iNumThreads; i++) - m_vecpThread[i]->Run(); - + ReconstructorSupervisor reconSupervisor (this, m_pProjView, m_iNX, m_iNY, + m_strFilterName.c_str(), m_dFilterParam, m_strFilterMethod.c_str(), m_iZeropad, m_strFilterGenerationName.c_str(), + m_strInterpName.c_str(), m_iInterpParam, m_strBackprojectName.c_str(), m_strLabel.c_str()); + + reconSupervisor.start(); + while (! reconSupervisor.isDone() && ! reconSupervisor.fail()) { + Sleep(100); + Yield(); + } + if (reconSupervisor.fail()) + { + wxString msg ("Error starting reconstructor supervisor: "); + msg += reconSupervisor.getFailMessage().c_str(); + msg += "\n"; + wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); + eventLog.SetString( msg ); + wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event + } - if (m_bCancelled) - return false; + while (! reconSupervisor.workersDeleted()) { + Sleep(50); + reconSupervisor.ProcessPendingEvents(); + } - return true; + return reinterpret_cast(0); } void -ThreadedReconstructor::cancel() +ReconstructorSupervisorThread::OnExit() { - if (m_bCancelled) - return; - - wxCriticalSectionLocker locker (m_criticalSection); +} - for (int i = 0; i < m_iNumThreads; i++) - if (m_vecpThread[i]) - m_vecpThread[i]->Delete(); - for (i = 0; i < m_iNumThreads; i++) - delete m_vecpReconstructor[i]; +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorSupervisor -- A Background Supervisor +// +///////////////////////////////////////////////////////////////////// + +ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, ProjectionFileView* pProjView, + int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, + int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, + const char* pszBackprojectName, const char* const pszLabel) + : m_pProjView(pProjView), m_pProjDoc(pProjView->GetDocument()), + m_iImageNX(iImageNX), m_iImageNY(iImageNY), + m_pszFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_pszFilterMethod(pszFilterMethod), + m_iZeropad(iZeropad), m_pszFilterGenerationName(pszFilterGenerationName), m_pszInterpName(pszInterpName), + m_iInterpParam(iInterpParam), m_pszBackprojectName(pszBackprojectName), m_pszLabel(pszLabel), + BackgroundSupervisor (pThread, pProjView->GetFrame(), pProjView->GetDocument(), "Reconstructing", pProjView->GetDocument()->getProjections().nView()) +{ + m_vecpChildImageFile.reserve (getNumWorkers()); + for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) { + m_vecpChildImageFile[iThread] = new ImageFile (iImageNX, iImageNY); + } - m_iNumThreads = 0; - m_iRunning = 0; - delete m_pDialogProgress; - delete m_pTimer; - m_pDialogProgress = NULL; - m_pProjView->GetDocument()->removeReconstructor (this); - m_bCancelled = true; - m_bDone = true; - // theApp->removeBackgroundTask (this); } -void -ThreadedReconstructor::onDone() +ReconstructorSupervisor::~ReconstructorSupervisor() { - for (int i = 0; i < m_iNumThreads; i++) - delete m_vecpReconstructor[i]; - - m_pProjView->GetDocument()->removeReconstructor (this); - ImageFileDocument* pReconDoc = theApp->newImageDoc(); - if (! pReconDoc) { - sys_error (ERR_SEVERE, "Unable to create image file"); - return; - } - - ImageFile* pImageFile = getImageFile(); - pReconDoc->setImageFile (pImageFile); - if (theApp->getAskDeleteNewDocs()) - pReconDoc->Modify (true); - pReconDoc->UpdateAllViews (m_pProjView); - if (ImageFileView* rasterView = pReconDoc->getView()) { - rasterView->OnUpdate (rasterView, NULL); - rasterView->getFrame()->SetFocus(); - rasterView->getFrame()->Show(true); - } - *theApp->getLog() << m_strLabel << "\n"; - pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel()); - pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd()); - delete m_pTimer; - - wxIdleEvent event; - theApp->OnIdle(event); - m_bDone = true; - // theApp->removeBackgroundTask (this); - // delete this; + for (int i = 0; i < getNumWorkers(); i++) { + delete m_vecpChildImageFile[i]; + m_vecpChildImageFile[i] = NULL; + } } +BackgroundWorkerThread* +ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits) +{ + ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits); + pThread->SetParameters (m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName, m_dFilterParam, + m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName, + m_iInterpParam, m_pszBackprojectName); + + return pThread; +} void -ThreadedReconstructor::OnThreadEvent (wxCommandEvent& event) +ReconstructorSupervisor::onDone() { - if (m_bCancelling) { - cancel(); + wxCriticalSection doneSection; + wxCriticalSectionLocker critsect (doneSection); + + ImageFileDocument* pReconDoc = theApp->newImageDoc(); + if (! pReconDoc) { + sys_error (ERR_SEVERE, "Unable to create image file"); return; } - - wxCriticalSectionLocker locker (m_criticalSection); - - int iEventId = event.GetInt(); - if (iEventId == RTHREAD_UNIT_COMPLETE) { - ++m_iViewsDone; - *theApp->getLog() << "Views done: " << static_cast(m_iViewsDone) <<"\n"; - - if (m_pDialogProgress) - m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1); - - // m_bCancelling = theApp->updateBackgroundTask (this, m_iViewsDone); - if (m_iViewsDone == m_iTotalViews) { - delete m_pDialogProgress; - m_pDialogProgress = NULL; - onDone(); - } - if (m_bCancelling) { - cancel(); - return; - } - } - else if (event.GetInt() >= 0) { - m_iRunning--; - m_vecpThread[event.GetInt()] = NULL; - *theApp->getLog() << "Thread finished. Remaining threads: " << m_iRunning << "\n"; + + ImageFile* pImageFile = getImageFile(); + pReconDoc->setImageFile (pImageFile); + if (theApp->getAskDeleteNewDocs()) + pReconDoc->Modify (true); + pReconDoc->UpdateAllViews (m_pProjView); + if (ImageFileView* rasterView = pReconDoc->getView()) { + rasterView->OnUpdate (rasterView, NULL); + rasterView->getFrame()->SetFocus(); + rasterView->getFrame()->Show(true); } - else - *theApp->getLog() << "Got event #" << iEventId << "\n"; + *theApp->getLog() << m_pszLabel << "\n"; + pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel()); + pImageFile->labelAdd (m_pszLabel, getTimerEnd()); + setDone(); } + ImageFile* -ThreadedReconstructor::getImageFile() const +ReconstructorSupervisor::getImageFile() { ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY); pImageFile->arrayDataClear(); ImageFileArray pArray = pImageFile->getArray(); - + int i; - for (i = 0; i < m_iNumThreads; i++) { + for (i = 0; i < getNumWorkers(); i++) { ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray(); for (int ix = 0; ix < m_iImageNX; ix++) for (int iy = 0; iy < m_iImageNY; iy++) pArray[ix][iy] += pChildArray[ix][iy]; } - - for (i = 0; i < m_iNumThreads; i++) { - delete m_vecpChildImageFile[i]; -// m_vecpChildImageFile[i] = NULL; - } - + return (pImageFile); } -bool -ThreadedReconstructor::testDone() -{ - return (m_iRunning <= 0 ? true : false); -} - -ThreadedReconstructor::~ThreadedReconstructor() -{ -} +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorWorker -- A worker thread +// +///////////////////////////////////////////////////////////////////// - -ReconstructionThread::ReconstructionThread (ThreadedReconstructor* pSupervisor, - Reconstructor* pReconstructor, int iThread, int iStartView, int iNumViews) -: m_pSupervisor(pSupervisor), m_pReconstructor(pReconstructor), - m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread), - wxThread(wxTHREAD_DETACHED) +void +ReconstructorWorker::SetParameters (ProjectionFileView* pProjView, ImageFile* pImageFile, + const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad, + const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, + const char* pszBackprojectName) { + m_pProjView = pProjView; + m_pImageFile = pImageFile; + m_pszFilterName = pszFilterName; + m_dFilterParam = dFilterParam; + m_pszFilterMethod = pszFilterMethod; + m_iZeropad = iZeropad; + m_pszFilterGenerationName = pszFilterGenerationName; + m_pszInterpName = pszInterpName; + m_iInterpParam = iInterpParam; + m_pszBackprojectName = pszBackprojectName; } wxThread::ExitCode -ReconstructionThread::Entry () +ReconstructorWorker::Entry () { - wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, RECONSTRUCTION_THREAD_EVENT); - for (int iView = 0; iView < m_iNumViews; iView++) { - if (TestDestroy()) { - wxString msg; - msg.Printf("TestDestroy TRUE at view #%d\n", iView); + Reconstructor* pReconstructor = new Reconstructor (m_pProjView->GetDocument()->getProjections(), + *m_pImageFile, m_pszFilterName, m_dFilterParam, m_pszFilterMethod, m_iZeropad, + m_pszFilterGenerationName, m_pszInterpName, m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE); + + bool bFail = pReconstructor->fail(); + wxString failMsg; + if (bFail) { + failMsg = "Unable to make reconstructor: "; + failMsg += pReconstructor->failMessage().c_str(); wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); - event.SetString( msg ); - wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way - return reinterpret_cast(RTHREAD_THREAD_CANCELLED); - } - m_pReconstructor->reconstructView (iView + m_iStartView, 1); - eventProgress.SetInt (RTHREAD_UNIT_COMPLETE); - wxPostEvent (m_pSupervisor, eventProgress); - } - - eventProgress.SetInt (m_iThread); // Send back thread# that has finished - wxPostEvent (m_pSupervisor, eventProgress); - - return reinterpret_cast(0); + event.SetString( failMsg ); + wxPostEvent( theApp->getMainFrame(), event ); + } + else + { + wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK); + for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) { + if (TestDestroy()) { +#ifdef DEBUG + if (theApp->getVerboseLogging()) { + wxString msg; + msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit); + wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); + event.SetString( msg ); + wxPostEvent( theApp->getMainFrame(), event ); + } +#endif + break; + } + pReconstructor->reconstructView (iUnit + m_iStartUnit, 1); + m_pSupervisor->AddPendingEvent (eventProgress); + } + pReconstructor->postProcessing(); + } + delete pReconstructor; + + if (bFail) { + wxCommandEvent eventFail (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL); + eventFail.SetInt (m_iThread); // Send back thread# that has finished + eventFail.SetString (failMsg); + wxPostEvent (m_pSupervisor, eventFail); + } else { + wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE); + eventDone.SetInt (m_iThread); // Send back thread# that has finished + wxPostEvent (m_pSupervisor, eventDone); + } + + while (! TestDestroy()) + Sleep(100); + + return reinterpret_cast(0); } void -ReconstructionThread::OnExit () +ReconstructorWorker::OnExit () { }