Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkNonBlockingAlgorithm.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
19 #include "mitkDataStorage.h"
20 #include <itkCommand.h>
21 
22 namespace mitk
23 {
24  NonBlockingAlgorithm::NonBlockingAlgorithm() : m_ThreadID(-1), m_UpdateRequests(0), m_KillRequest(false)
25  {
26  m_ParameterListMutex = itk::FastMutexLock::New();
28  m_MultiThreader = itk::MultiThreader::New();
29  }
30 
32  void mitk::NonBlockingAlgorithm::SetDataStorage(DataStorage &storage) { m_DataStorage = &storage; }
35  {
36  // define one input, one output basedata object
37 
38  // some basedata input - image, surface, whatever
39  BaseData::Pointer input;
40  SetPointerParameter("Input", input);
41 
42  // some basedata output
43  BaseData::Pointer output;
44  SetPointerParameter("Output", output);
45  }
46 
47  void NonBlockingAlgorithm::SetPointerParameter(const char *parameter, BaseData *value)
48  {
49  m_ParameterListMutex->Lock();
50  m_Parameters->SetProperty(parameter, SmartPointerProperty::New(value));
51  m_ParameterListMutex->Unlock();
52  }
53 
55  {
56  BaseProperty *value = m_Parameters->GetProperty(parameter);
57  if (value && m_TriggerPropertyConnections.find(parameter) == m_TriggerPropertyConnections.end())
58  {
61  command->SetCallbackFunction(this, &NonBlockingAlgorithm::TriggerParameterModified);
62 
63  m_TriggerPropertyConnections[parameter] = value->AddObserver(itk::ModifiedEvent(), command);
64  }
65  }
66 
68  {
69  auto iter = m_TriggerPropertyConnections.find(parameter);
70 
71  if (iter != m_TriggerPropertyConnections.end())
72  {
73  BaseProperty *value = m_Parameters->GetProperty(parameter);
74 
75  MITK_ERROR(!value) << "NonBlockingAlgorithm::UnDefineTriggerProperty() in bad state." << std::endl;
76  ;
77 
78  value->RemoveObserver(m_TriggerPropertyConnections[parameter]);
79  m_TriggerPropertyConnections.erase(iter);
80  }
81  }
82 
85  {
87  StopAlgorithm();
88  }
89 
91  {
92  if (!ReadyToRun())
93  return; // let algorithm check if all input/parameters are ok
94  if (m_KillRequest)
95  return; // someone wants us to die
96 
97  m_ParameterListMutex->Lock();
98  m_ThreadParameters.m_Algorithm = this;
99  ++m_UpdateRequests;
100  m_ParameterListMutex->Unlock();
101  if (m_ThreadID != -1) // thread already running. But something obviously wants us to recalculate the output
102  {
103  return; // thread already running
104  }
105 
106  // spawn a thread that calls ThreadedUpdateFunction(), and ThreadedUpdateFinished() on us
107  itk::ThreadFunctionType fpointer = &StaticNonBlockingAlgorithmThread;
108  m_ThreadID = m_MultiThreader->SpawnThread(fpointer, &m_ThreadParameters);
109  }
110 
112  {
113  if (m_ThreadID == -1)
114  return; // thread not running
115 
116  m_MultiThreader->TerminateThread(m_ThreadID); // waits for the thread to terminate on its own
117  }
118 
119  // a static function to call a member of NonBlockingAlgorithm from inside an ITK thread
120  ITK_THREAD_RETURN_TYPE NonBlockingAlgorithm::StaticNonBlockingAlgorithmThread(void *param)
121  {
122  // itk::MultiThreader provides an itk::MultiThreader::ThreadInfoStruct as parameter
123  itk::MultiThreader::ThreadInfoStruct *itkmttis = static_cast<itk::MultiThreader::ThreadInfoStruct *>(param);
124 
125  // we need the UserData part of that structure
126  ThreadParameters *flsp = static_cast<ThreadParameters *>(itkmttis->UserData);
127 
128  NonBlockingAlgorithm::Pointer algorithm = flsp->m_Algorithm;
129  // this UserData tells us, which BubbleTool's method to call
130  if (!algorithm)
131  {
132  return ITK_THREAD_RETURN_VALUE;
133  }
134 
135  algorithm->m_ParameterListMutex->Lock();
136  while (algorithm->m_UpdateRequests > 0)
137  {
138  algorithm->m_UpdateRequests = 0;
139  algorithm->m_ParameterListMutex->Unlock();
140 
141  // actually call the methods that do the work
142  if (algorithm->ThreadedUpdateFunction()) // returns a bool for success/failure
143  {
146  command->SetCallbackFunction(algorithm, &NonBlockingAlgorithm::ThreadedUpdateSuccessful);
148  // algorithm->ThreadedUpdateSuccessful();
149  }
150  else
151  {
154  command->SetCallbackFunction(algorithm, &NonBlockingAlgorithm::ThreadedUpdateFailed);
156  // algorithm->ThreadedUpdateFailed();
157  }
158 
159  algorithm->m_ParameterListMutex->Lock();
160  }
161  algorithm->m_ParameterListMutex->Unlock();
162 
163  return ITK_THREAD_RETURN_VALUE;
164  }
165 
168  {
169  return true; // default is always ready
170  }
171 
173  // called from gui thread
174  void NonBlockingAlgorithm::ThreadedUpdateSuccessful(const itk::EventObject &)
175  {
177 
178  m_ParameterListMutex->Lock();
179  m_ThreadID = -1; // tested before starting
180  m_ParameterListMutex->Unlock();
181  m_ThreadParameters.m_Algorithm = nullptr;
182  }
183 
185  {
186  // notify observers that a result is ready
187  InvokeEvent(ResultAvailable(this));
188  }
189 
190  // called from gui thread
191  void NonBlockingAlgorithm::ThreadedUpdateFailed(const itk::EventObject &)
192  {
194 
195  m_ParameterListMutex->Lock();
196  m_ThreadID = -1; // tested before starting
197  m_ParameterListMutex->Unlock();
198  m_ThreadParameters.m_Algorithm = nullptr; // delete
199  }
200 
202  {
203  // notify observers that something went wrong
204  InvokeEvent(ProcessingError(this));
205  }
206 
207 } // namespace
itk::SmartPointer< NonBlockingAlgorithm > m_Algorithm
Data management class that handles 'was created by' relations.
itk::SmartPointer< Self > Pointer
static Pointer New()
Base of all data objects.
Definition: mitkBaseData.h:39
#define MITK_ERROR
Definition: mitkLogMacros.h:24
virtual void Initialize(const NonBlockingAlgorithm *other=nullptr)
DataCollection - Class to facilitate loading/accessing structured data.
Abstract base class for properties.
mitk::DataStorage::Pointer m_DataStorage
void CallThisFromGUIThread(itk::Command *, itk::EventObject *e=nullptr)
Change the current application cursor.
static CallbackFromGUIThread * GetInstance()
This class is a singleton.
void TriggerParameterModified(const itk::EventObject &)
void SetPointerParameter(const char *parameter, const itk::SmartPointer< T > &value)
For any kind of smart pointers.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.