** This is part of the CTSim program
** Copyright (C) 1983-2001 Kevin Rosenberg
**
-** $Id: threadrecon.cpp,v 1.3 2001/02/22 18:22:40 kevin Exp $
+** $Id: threadrecon.cpp,v 1.6 2001/02/23 18:56:56 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
#endif
-IMPLEMENT_DYNAMIC_CLASS(ThreadedReconstructor, BackgroundTask)
-BEGIN_EVENT_TABLE(ThreadedReconstructor, BackgroundTask)
-EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ThreadedReconstructor::OnThreadEvent)
+IMPLEMENT_DYNAMIC_CLASS(ReconstructorSupervisor, BackgroundSupervisor)
+BEGIN_EVENT_TABLE(ReconstructorSupervisor, BackgroundSupervisor)
+EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ReconstructorSupervisor::OnThreadEvent)
+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()
-enum {
- RTHREAD_UNIT_COMPLETE = -1,
- RTHREAD_THREAD_DONE = -2,
- RTHREAD_THREAD_CANCELLED = -3,
-};
-
-ThreadedReconstructor::ThreadedReconstructor (ProjectionFileView* pProjView,
+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_pProjView(pProjView), m_pDialogProgress(NULL), m_pGauge(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),
- BackgroundTask()
+ BackgroundSupervisor()
{
m_iNumThreads = theApp->getNumberCPU();
// ++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);
+ 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;
bool
-ThreadedReconstructor::start()
+ReconstructorSupervisor::start()
{
if (m_bFail)
return false;
m_pProjView->GetDocument()->addReconstructor (this);
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
- m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, m_pProjView->GetFrame()->GetTitle());
+ else {
+ std::string strLabel ("Reconstructing ");
+ strLabel += m_pProjView->GetFrame()->GetTitle();
+ m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, strLabel.c_str());
+ }
m_iRunning = m_iNumThreads;
m_iViewsDone = 0;
}
void
-ThreadedReconstructor::cancel()
+ReconstructorSupervisor::cancel()
{
if (isDone() || m_bCancelled)
return;
}
void
-ThreadedReconstructor::cleanUp()
+ReconstructorSupervisor::cleanUp()
{
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();
}
+ m_critsectThreadContainer.Leave();
- for (i = 0; i < m_iNumThreads; i++) {
+ for (i = 0; i < m_iNumThreads; i++) {
delete m_vecpChildImageFile[i];
m_vecpChildImageFile[i] = NULL;
- }
- for (i = 0; i < m_iNumThreads; i++) {
- delete m_vecpReconstructor[i];
- m_vecpReconstructor[i] = NULL;
- }
-
+ }
m_iNumThreads = 0;
m_iRunning = 0;
}
void
-ThreadedReconstructor::onDone()
+ReconstructorSupervisor::onDone()
{
wxCriticalSection doneSection;
doneSection.Enter();
-
+
m_pProjView->GetDocument()->removeReconstructor (this);
ImageFileDocument* pReconDoc = theApp->newImageDoc();
if (! pReconDoc) {
doneSection.Leave();
return;
}
-
- for (int i = 0; i < m_iNumThreads; i++) {
- delete m_vecpReconstructor[i];
- m_vecpReconstructor[i] = NULL;
- }
-
+
ImageFile* pImageFile = getImageFile();
pReconDoc->setImageFile (pImageFile);
if (theApp->getAskDeleteNewDocs())
cleanUp();
}
-
void
-ThreadedReconstructor::OnThreadEvent (wxCommandEvent& event)
+ReconstructorSupervisor::OnWorkerUnitTick (wxCommandEvent& event)
{
- if (isDone())
- return;
- wxCriticalSection eventSection;
- eventSection.Enter();
- if (isDone()) {
- eventSection.Leave();
- return;
- }
-
- int iEventId = event.GetInt();
- if (iEventId == RTHREAD_UNIT_COMPLETE) {
++m_iViewsDone;
#ifdef DEBUG
m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1);
else if (m_pGauge) {
m_pGauge->SetValue (m_iViewsDone - 1);
- eventSection.Leave();
m_bCancelling = theApp->getBackgroundManager()->isCancelling(this);
}
if (! isDone() && m_bCancelling) {
- eventSection.Leave();
cancel();
return;
}
- }
- else if (event.GetInt() >= 0) {
- m_iRunning--;
- m_vecpThread[event.GetInt()] = NULL;
- *theApp->getLog() << "Thread finished. Remaining threads: " << m_iRunning << "\n";
- if (m_iRunning <= 0) {
- eventSection.Leave();
- onDone();
- return;
- }
+}
+
+void
+ReconstructorSupervisor::OnWorkerDone (wxCommandEvent& event)
+{
+ if (isDone())
+ return;
+
+ m_iRunning--;
+ m_critsectThreadContainer.Enter();
+ m_vecpThread[event.GetInt()] = NULL;
+ m_critsectThreadContainer.Leave();
+ 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
+
+ if (m_iRunning <= 0) {
+ onDone();
+ return;
}
- else
- *theApp->getLog() << "Got event #" << iEventId << "\n";
-
- eventSection.Leave();
+}
+
+void
+ReconstructorSupervisor::OnWorkerFail (wxCommandEvent& event)
+{
+ 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() );
+ wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
+
+ onDone();
+}
+
+
+void
+ReconstructorSupervisor::OnThreadEvent (wxCommandEvent& event)
+{
+ wxString msg;
+ msg.Printf("Reconstructor Supervisor: Received event #%d\n", event.GetInt());
+ wxCommandEvent eventLog( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+ eventLog.SetString( msg );
+ wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
}
ImageFile*
-ThreadedReconstructor::getImageFile()
+ReconstructorSupervisor::getImageFile()
{
ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
pImageFile->arrayDataClear();
}
bool
-ThreadedReconstructor::testDone()
+ReconstructorSupervisor::testDone()
{
return (m_iRunning <= 0 ? true : false);
}
-ThreadedReconstructor::~ThreadedReconstructor()
+ReconstructorSupervisor::~ReconstructorSupervisor()
{
}
-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)
+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)
{
}
wxThread::ExitCode
-ReconstructionThread::Entry ()
+ReconstructorWorker::Entry ()
{
- wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, RECONSTRUCTION_THREAD_EVENT);
+ 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);
+ }
+
+ wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
+
for (int iView = 0; iView < m_iNumViews; iView++) {
if (TestDestroy()) {
+#ifdef DEBUG
wxString msg;
- msg.Printf("TestDestroy TRUE at view #%d\n", iView);
+ 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
- return reinterpret_cast<wxThread::ExitCode>(RTHREAD_THREAD_CANCELLED);
+#endif
+ delete pReconstructor;
+ return reinterpret_cast<wxThread::ExitCode>(-1);
}
- m_pReconstructor->reconstructView (iView + m_iStartView, 1);
- eventProgress.SetInt (RTHREAD_UNIT_COMPLETE);
+ pReconstructor->reconstructView (iView + m_iStartView, 1);
wxPostEvent (m_pSupervisor, eventProgress);
}
+ 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, eventProgress);
+ wxPostEvent (m_pSupervisor, eventDone);
+ delete pReconstructor;
return reinterpret_cast<wxThread::ExitCode>(0);
}
void
-ReconstructionThread::OnExit ()
+ReconstructorWorker::OnExit ()
{
}