** 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
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
+
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#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<wxThread::ExitCode>(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<int>(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*
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<wxThread::ExitCode>(-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<wxThread::ExitCode>(-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<wxThread::ExitCode>(0);
}
ReconstructorWorker::OnExit ()
{
}
+
+#endif // HAVE_WXTHREADS