X-Git-Url: http://git.kpe.io/?p=ctsim.git;a=blobdiff_plain;f=src%2Fthreadrecon.cpp;h=8c5cb0574bb95303874236030868877a639b0332;hp=0fd94b293460292533316dd82abbdab4ad0b17eb;hb=f7ee98f7d964ed361068179f0e7ea4475ed1abdf;hpb=6480e936da257519dd36840862ac995ca8c374da diff --git a/src/threadrecon.cpp b/src/threadrecon.cpp index 0fd94b2..8c5cb05 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.7 2001/02/23 21:58:32 kevin Exp $ +** $Id$ ** ** 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 @@ -25,6 +25,7 @@ ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************************************/ + #include "wx/wxprec.h" #ifndef WX_PRECOMP @@ -37,232 +38,140 @@ #include "views.h" #include "threadrecon.h" #include "backgroundmgr.h" +#include "backgroundsupr.h" + +#ifdef HAVE_WXTHREADS -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif -IMPLEMENT_DYNAMIC_CLASS(ReconstructorSupervisor, BackgroundSupervisor) -BEGIN_EVENT_TABLE(ReconstructorSupervisor, BackgroundSupervisor) -EVT_MENU(MSG_BACKGROUND_SUPERVISOR_CANCEL, ReconstructorSupervisor::OnCancel) -EVT_MENU(MSG_WORKER_THREAD_FAIL, ReconstructorSupervisor::OnWorkerFail) -EVT_MENU(MSG_WORKER_THREAD_DONE, ReconstructorSupervisor::OnWorkerDone) -EVT_MENU(MSG_WORKER_THREAD_UNIT_TICK, ReconstructorSupervisor::OnWorkerUnitTick) -END_EVENT_TABLE() +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorSupervisorThread -- Thread for Background Supervisor +// +///////////////////////////////////////////////////////////////////// -ReconstructorSupervisor::ReconstructorSupervisor (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_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), - BackgroundSupervisor() +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, wxChar const* pszLabel, ReconstructionROI* pROI, bool bRebinToParallel) +: SupervisorThread(), 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), m_reconROI(*pROI), m_bRebinToParallel(bRebinToParallel) { - m_iNumThreads = theApp->getNumberCPU(); - // ++m_iNumThreads; - m_iTotalViews = pProjView->GetDocument()->getProjections().nView(); - int iBaseViews = m_iTotalViews / m_iNumThreads; - int iExtraViews = m_iTotalViews % m_iNumThreads; - - m_vecpChildImageFile.reserve (m_iNumThreads); - m_vecpThread.reserve (m_iNumThreads); - - for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) { - m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY); - - int iStartView = iProc * iBaseViews; - int iNumViews = iBaseViews; - if (iProc < iExtraViews) - ++iNumViews; - m_vecpThread[iProc] = new ReconstructorWorker (this, pProjView, m_vecpChildImageFile[iProc], iProc, iStartView, iNumViews, - pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName, pszInterpName, iInterpParam, pszBackprojectName); - if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) { - m_bFail = true; - break; - } - } - m_pProjView = pProjView; - m_pProjDoc = pProjView->GetDocument(); } -// Static function -void -BackgroundSupervisor::cancelSupervisor (BackgroundSupervisor* pSupervisor) +wxThread::ExitCode +ReconstructorSupervisorThread::Entry() { - wxCommandEvent cancelEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_CANCEL); - wxPostEvent (pSupervisor, cancelEvent); -} + Projections* pProj = &m_pProjView->GetDocument()->getProjections(); + if (m_bRebinToParallel) + pProj = pProj->interpolateToParallel(); -bool -ReconstructorSupervisor::start() -{ - if (m_bFail) - return false; - - if (! theApp->getUseBackgroundTasks()) - m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, m_pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE); - else { - std::string strLabel ("Reconstructing "); - strLabel += m_pProjView->GetFrame()->GetTitle(); - wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_ADD); - addTaskEvent.SetString (strLabel.c_str()); - addTaskEvent.SetInt (m_iTotalViews); - addTaskEvent.SetClientData (this); - wxPostEvent (theApp->getBackgroundManager(), addTaskEvent); - wxPostEvent (m_pProjDoc, addTaskEvent); + ReconstructorSupervisor reconSupervisor (this, pProj, 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, &m_reconROI); + + reconSupervisor.start(); + while (! reconSupervisor.workersDone() && ! reconSupervisor.fail() && ! reconSupervisor.cancelled()) { + Sleep(100); } - - m_iRunning = m_iNumThreads; - m_iViewsDone = 0; - m_pTimer = new Timer; - - // starting all threads - for (int i = 0; i < m_iNumThreads; i++) - m_vecpThread[i]->Run(); - - return true; -} + if (reconSupervisor.fail()) + { + wxString msg (_T("Error starting reconstructor supervisor: ")); + msg += reconSupervisor.getFailMessage(); + msg += _T("\n"); + wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); + eventLog.SetString( msg ); + wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event + } + if (! reconSupervisor.cancelled()) + reconSupervisor.onDone(); + reconSupervisor.deleteWorkers(); -void -ReconstructorSupervisor::OnCancel(wxCommandEvent& event) -{ - if (isDone() || m_bCancelled) - return; - m_bCancelled = true; - m_bCancelling = false; - cleanUp(); + if (m_bRebinToParallel) + delete pProj; + + return static_cast(0); } void -ReconstructorSupervisor::cleanUp() +ReconstructorSupervisorThread::OnExit() { - wxCriticalSection cleanSection; - cleanSection.Enter(); - - m_critsectThreadContainer.Enter(); - for (int i = 0; i < m_iNumThreads; i++) - if (m_vecpThread[i] && m_vecpThread[i]->IsRunning()) { - m_vecpThread[i]->Pause(); - m_vecpThread[i]->Delete(); - } - - for (i = 0; i < m_iNumThreads; i++) { - delete m_vecpChildImageFile[i]; - m_vecpChildImageFile[i] = NULL; - } - m_critsectThreadContainer.Leave(); - - m_iNumThreads = 0; - m_iRunning = 0; - delete m_pDialogProgress; - delete m_pTimer; - m_pDialogProgress = NULL; - setDone(); - - wxCommandEvent doneEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_REMOVE); - doneEvent.SetClientData (this); - wxPostEvent (theApp->getBackgroundManager(), doneEvent); - wxPostEvent (m_pProjDoc, doneEvent); - - cleanSection.Leave(); } -void -ReconstructorSupervisor::onDone() + +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorSupervisor -- A Background Supervisor +// +///////////////////////////////////////////////////////////////////// + +ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, Projections* pProj, + 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, wxChar const* pszLabel, + ReconstructionROI* pROI) + : BackgroundSupervisor (pThread, pProjView->GetFrame(), pProjView->GetDocument(), + _T("Reconstructing"), + pProjView->GetDocument()->getProjections().nView()), + m_pProj(pProj), 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_strLabel(pszLabel), + m_pReconROI(pROI) { - wxCriticalSection doneSection; - doneSection.Enter(); - - - ImageFileDocument* pReconDoc = theApp->newImageDoc(); - if (! pReconDoc) { - sys_error (ERR_SEVERE, "Unable to create image file"); - doneSection.Leave(); - 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); + m_vecpChildImageFile.reserve (getNumWorkers()); + for (int iThread = 0; iThread < getNumWorkers(); iThread++) { + m_vecpChildImageFile[iThread] = new ImageFile (m_iImageNX, m_iImageNY); } - *theApp->getLog() << m_strLabel << "\n"; - pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel()); - pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd()); - - doneSection.Leave(); - cleanUp(); + } -void -ReconstructorSupervisor::OnWorkerUnitTick (wxCommandEvent& event) +ReconstructorSupervisor::~ReconstructorSupervisor() { - ++m_iViewsDone; - -#ifdef DEBUG - if (theApp->getVerboseLogging()) - *theApp->getLog() << "Views done: " << static_cast(m_iViewsDone) <<"\n"; -#endif - - if (m_pDialogProgress) - m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1); - else { - wxCommandEvent addTaskEvent (wxEVT_COMMAND_MENU_SELECTED, MSG_BACKGROUND_SUPERVISOR_UNIT_TICK); - addTaskEvent.SetInt (m_iViewsDone - 1); - addTaskEvent.SetClientData (this); - wxPostEvent (theApp->getBackgroundManager(), addTaskEvent); + for (int i = 0; i < getNumWorkers(); i++) { + delete m_vecpChildImageFile[i]; + m_vecpChildImageFile[i] = NULL; } } -void -ReconstructorSupervisor::OnWorkerDone (wxCommandEvent& event) +BackgroundWorkerThread* +ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits) { - m_iRunning--; - wxASSERT (m_iRunning >= 0); - m_critsectThreadContainer.Enter(); - m_vecpThread[event.GetInt()] = NULL; - m_critsectThreadContainer.Leave(); + ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits); + pThread->SetParameters (m_pProj, m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName, + m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName, + m_iInterpParam, m_pszBackprojectName, m_pReconROI); -#ifdef DEBUG - if (theApp->getVerboseLogging()) { - wxString msg; - msg.Printf("Reconstructor Supervisor: Thread finished. Remaining threads: %d\n", m_iRunning); - wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); - eventLog.SetString( msg ); - wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event - } -#endif - if (m_iRunning <= 0) { - onDone(); - return; - } + return pThread; } void -ReconstructorSupervisor::OnWorkerFail (wxCommandEvent& event) +ReconstructorSupervisor::onDone() { - if (isDone()) - return; - - m_iRunning--; - m_critsectThreadContainer.Enter(); - m_vecpThread[event.GetInt()] = NULL; - m_critsectThreadContainer.Leave(); - wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); - eventLog.SetString( event.GetString() ); + wxCriticalSection doneSection; + wxCriticalSectionLocker critsect (doneSection); + + ImageFile* pImageFile = getImageFile(); + pImageFile->labelAdd (m_pProj->getLabel()); + pImageFile->labelAdd (m_strLabel.mb_str(wxConvUTF8), getTimerEnd()); + + wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); + wxString msg (m_strLabel); + msg += _T("\n"); + eventLog.SetString( msg ); wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event - onDone(); -} + wxCommandEvent newImageEvent (wxEVT_COMMAND_MENU_SELECTED, NEW_IMAGEFILE_EVENT); + newImageEvent.SetClientData (pImageFile); + wxPostEvent (theApp->getMainFrame(), newImageEvent); + setDone(); +} ImageFile* @@ -271,82 +180,93 @@ 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]; } - - return (pImageFile); -} -bool -ReconstructorSupervisor::testDone() -{ - return (m_iRunning <= 0 ? true : false); + return (pImageFile); } -ReconstructorSupervisor::~ReconstructorSupervisor() -{ -} - +///////////////////////////////////////////////////////////////////// +// +// Class ReconstructorWorker -- A worker thread +// +///////////////////////////////////////////////////////////////////// -ReconstructorWorker::ReconstructorWorker -(ReconstructorSupervisor* pSupervisor, ProjectionFileView* pProjView, ImageFile* pImageFile, int iThread, int iStartView, int iNumViews, - const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, - int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, - const char* pszBackprojectName) - : m_pSupervisor(pSupervisor), m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread), - m_pProjView(pProjView), m_pImageFile(pImageFile), m_strFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_strFilterMethod(pszFilterMethod), - m_iZeropad(iZeropad), m_strFilterGenerationName(pszFilterGenerationName), m_strInterpName(pszInterpName), - m_iInterpParam(iInterpParam), m_strBackprojectName(pszBackprojectName), - wxThread(wxTHREAD_DETACHED) +void +ReconstructorWorker::SetParameters (const Projections* pProj, 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, ReconstructionROI* pROI) { + m_pProj = pProj; + 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; + m_pReconROI = pROI; } wxThread::ExitCode ReconstructorWorker::Entry () { - Reconstructor* pReconstructor = new Reconstructor (m_pProjView->GetDocument()->getProjections(), - *m_pImageFile, 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(), Trace::TRACE_NONE); - if (pReconstructor->fail()) { - wxString msg; - msg.Printf("Unable to make reconstructor: %s", pReconstructor->failMessage()); - wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL ); - event.SetString( msg ); - wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way - return reinterpret_cast(-1); + Reconstructor* pReconstructor = new Reconstructor (*m_pProj, *m_pImageFile, m_pszFilterName, + m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName, + m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE, m_pReconROI, false); + + bool bFail = pReconstructor->fail(); + wxString failMsg; + if (bFail) { + failMsg = _T("Unable to make reconstructor: "); + failMsg += wxConvUTF8.cMB2WX(pReconstructor->failMessage().c_str()); + wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); + event.SetString( failMsg ); + wxPostEvent( theApp->getMainFrame(), event ); } - - wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK); - - for (int iView = 0; iView < m_iNumViews; iView++) { - if (TestDestroy()) { + 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 - wxString msg; - msg.Printf("Received destroy message view #%d\n", iView); - wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT ); - event.SetString( msg ); - wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way + if (theApp->getVerboseLogging()) { + wxString msg; + msg.Printf(_T("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 - delete pReconstructor; - return reinterpret_cast(-1); + break; + } + pReconstructor->reconstructView (iUnit + m_iStartUnit, 1); + m_pSupervisor->onWorkerUnitTick(); } - pReconstructor->reconstructView (iView + m_iStartView, 1); - wxPostEvent (m_pSupervisor, eventProgress); + pReconstructor->postProcessing(); } - pReconstructor->postProcessing(); - - wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE); - eventProgress.SetInt (m_iThread); // Send back thread# that has finished - wxPostEvent (m_pSupervisor, eventDone); - delete pReconstructor; + + if (bFail) { + m_pSupervisor->onWorkerFail (m_iThread, failMsg); + } else { + m_pSupervisor->onWorkerDone (m_iThread); + } + + while (! TestDestroy()) + Sleep(100); + return reinterpret_cast(0); } @@ -354,3 +274,5 @@ void ReconstructorWorker::OnExit () { } + +#endif // HAVE_WXTHREADS