1 /*****************************************************************************
4 ** Name: threadrecon.cpp
5 ** Purpose: Threaded reconstruction class
6 ** Programmer: Kevin Rosenberg
7 ** Date Started: February 2001
9 ** This is part of the CTSim program
10 ** Copyright (C) 1983-2001 Kevin Rosenberg
12 ** $Id: threadrecon.cpp,v 1.4 2001/02/23 02:06:02 kevin Exp $
14 ** This program is free software; you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License (version 2) as
16 ** published by the Free Software Foundation.
18 ** This program is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ** GNU General Public License for more details.
23 ** You should have received a copy of the GNU General Public License
24 ** along with this program; if not, write to the Free Software
25 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ******************************************************************************/
28 #include "wx/wxprec.h"
38 #include "threadrecon.h"
39 #include "backgroundmgr.h"
41 #if defined(HAVE_CONFIG_H)
46 IMPLEMENT_DYNAMIC_CLASS(ThreadedReconstructor, BackgroundTask)
47 BEGIN_EVENT_TABLE(ThreadedReconstructor, BackgroundTask)
48 EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ThreadedReconstructor::OnThreadEvent)
53 RTHREAD_UNIT_COMPLETE = -1,
54 RTHREAD_THREAD_DONE = -2,
55 RTHREAD_THREAD_CANCELLED = -3,
58 ThreadedReconstructor::ThreadedReconstructor (ProjectionFileView* pProjView,
59 int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod,
60 int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
61 const char* pszBackprojectName, const char* const pszLabel)
62 : m_pProjView(pProjView), m_pDialogProgress(NULL), m_pGauge(NULL), m_bFail(false), m_iNumThreads(0), m_iImageNX(iImageNX),
63 m_iImageNY(iImageNY), m_strLabel(pszLabel), m_pTimer(NULL), m_bCancelled(false), m_bCancelling(false),
66 m_iNumThreads = theApp->getNumberCPU();
68 m_iTotalViews = m_pProjView->GetDocument()->getProjections().nView();
69 int iBaseViews = m_iTotalViews / m_iNumThreads;
70 int iExtraViews = m_iTotalViews % m_iNumThreads;
72 m_vecpChildImageFile.reserve (m_iNumThreads);
73 m_vecpReconstructor.reserve (m_iNumThreads);
74 m_vecpThread.reserve (m_iNumThreads);
76 for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) {
77 m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY);
78 m_vecpReconstructor[iProc] = new Reconstructor (m_pProjView->GetDocument()->getProjections(), *m_vecpChildImageFile[iProc],
79 pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName,
80 pszInterpName, iInterpParam, pszBackprojectName, Trace::TRACE_NONE);
82 int iStartView = iProc * iBaseViews;
83 int iNumViews = iBaseViews;
84 if (iProc < iExtraViews)
86 m_vecpThread[iProc] = new ReconstructionThread (this, m_vecpReconstructor[iProc], iProc, iStartView, iNumViews);
87 if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) {
97 ThreadedReconstructor::start()
102 m_pProjView->GetDocument()->addReconstructor (this);
103 if (! theApp->getUseBackgroundTasks())
104 m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, m_pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
106 std::string strLabel ("Reconstructing ");
107 strLabel += m_pProjView->GetFrame()->GetTitle();
108 m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, strLabel.c_str());
111 m_iRunning = m_iNumThreads;
113 m_pTimer = new Timer;
115 // starting all threads
116 for (int i = 0; i < m_iNumThreads; i++)
117 m_vecpThread[i]->Run();
126 ThreadedReconstructor::cancel()
128 if (isDone() || m_bCancelled)
131 m_bCancelling = false;
136 ThreadedReconstructor::cleanUp()
138 wxCriticalSection cleanSection;
139 cleanSection.Enter();
141 for (int i = 0; i < m_iNumThreads; i++)
142 if (m_vecpThread[i] && m_vecpThread[i]->IsRunning()) {
143 m_vecpThread[i]->Pause();
144 m_vecpThread[i]->Delete();
147 for (i = 0; i < m_iNumThreads; i++) {
148 delete m_vecpChildImageFile[i];
149 m_vecpChildImageFile[i] = NULL;
151 for (i = 0; i < m_iNumThreads; i++) {
152 delete m_vecpReconstructor[i];
153 m_vecpReconstructor[i] = NULL;
159 delete m_pDialogProgress;
161 m_pDialogProgress = NULL;
164 m_pProjView->GetDocument()->removeReconstructor (this);
165 theApp->getBackgroundManager()->taskDone (this);
167 cleanSection.Leave();
171 ThreadedReconstructor::onDone()
173 wxCriticalSection doneSection;
176 m_pProjView->GetDocument()->removeReconstructor (this);
177 ImageFileDocument* pReconDoc = theApp->newImageDoc();
179 sys_error (ERR_SEVERE, "Unable to create image file");
184 for (int i = 0; i < m_iNumThreads; i++) {
185 delete m_vecpReconstructor[i];
186 m_vecpReconstructor[i] = NULL;
189 ImageFile* pImageFile = getImageFile();
190 pReconDoc->setImageFile (pImageFile);
191 if (theApp->getAskDeleteNewDocs())
192 pReconDoc->Modify (true);
193 pReconDoc->UpdateAllViews (m_pProjView);
194 if (ImageFileView* rasterView = pReconDoc->getView()) {
195 rasterView->OnUpdate (rasterView, NULL);
196 rasterView->getFrame()->SetFocus();
197 rasterView->getFrame()->Show(true);
199 *theApp->getLog() << m_strLabel << "\n";
200 pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
201 pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd());
209 ThreadedReconstructor::OnThreadEvent (wxCommandEvent& event)
213 wxCriticalSection eventSection;
214 eventSection.Enter();
216 eventSection.Leave();
220 int iEventId = event.GetInt();
221 if (iEventId == RTHREAD_UNIT_COMPLETE) {
225 if (theApp->getVerboseLogging())
226 *theApp->getLog() << "Views done: " << static_cast<int>(m_iViewsDone) <<"\n";
229 if (m_pDialogProgress)
230 m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1);
232 m_pGauge->SetValue (m_iViewsDone - 1);
233 eventSection.Leave();
234 m_bCancelling = theApp->getBackgroundManager()->isCancelling(this);
236 if (! isDone() && m_bCancelling) {
237 eventSection.Leave();
242 else if (event.GetInt() >= 0) {
244 m_vecpThread[event.GetInt()] = NULL;
245 *theApp->getLog() << "Thread finished. Remaining threads: " << m_iRunning << "\n";
246 if (m_iRunning <= 0) {
247 eventSection.Leave();
253 *theApp->getLog() << "Got event #" << iEventId << "\n";
255 eventSection.Leave();
259 ThreadedReconstructor::getImageFile()
261 ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
262 pImageFile->arrayDataClear();
263 ImageFileArray pArray = pImageFile->getArray();
266 for (i = 0; i < m_iNumThreads; i++) {
267 ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
268 for (int ix = 0; ix < m_iImageNX; ix++)
269 for (int iy = 0; iy < m_iImageNY; iy++)
270 pArray[ix][iy] += pChildArray[ix][iy];
277 ThreadedReconstructor::testDone()
279 return (m_iRunning <= 0 ? true : false);
283 ThreadedReconstructor::~ThreadedReconstructor()
288 ReconstructionThread::ReconstructionThread (ThreadedReconstructor* pSupervisor,
289 Reconstructor* pReconstructor, int iThread, int iStartView, int iNumViews)
290 : m_pSupervisor(pSupervisor), m_pReconstructor(pReconstructor),
291 m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread),
292 wxThread(wxTHREAD_DETACHED)
297 ReconstructionThread::Entry ()
299 wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, RECONSTRUCTION_THREAD_EVENT);
300 for (int iView = 0; iView < m_iNumViews; iView++) {
303 msg.Printf("TestDestroy TRUE at view #%d\n", iView);
304 wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
305 event.SetString( msg );
306 wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way
307 return reinterpret_cast<wxThread::ExitCode>(RTHREAD_THREAD_CANCELLED);
309 m_pReconstructor->reconstructView (iView + m_iStartView, 1);
310 eventProgress.SetInt (RTHREAD_UNIT_COMPLETE);
311 wxPostEvent (m_pSupervisor, eventProgress);
313 m_pReconstructor->postProcessing();
315 eventProgress.SetInt (m_iThread); // Send back thread# that has finished
316 wxPostEvent (m_pSupervisor, eventProgress);
318 return reinterpret_cast<wxThread::ExitCode>(0);
322 ReconstructionThread::OnExit ()