Medical Imaging Interaction Toolkit  2018.4.99-4c24e3cb
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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
15 #include "mitkDataStorage.h"
16 #include <itkCommand.h>
17 
18 namespace mitk
19 {
20  NonBlockingAlgorithm::NonBlockingAlgorithm() : m_ThreadID(-1), m_UpdateRequests(0), m_KillRequest(false)
21  {
22  m_ParameterListMutex = itk::FastMutexLock::New();
24  m_MultiThreader = itk::MultiThreader::New();
25  }
26 
28  void mitk::NonBlockingAlgorithm::SetDataStorage(DataStorage &storage) { m_DataStorage = &storage; }
31  {
32  // define one input, one output basedata object
33 
34  // some basedata input - image, surface, whatever
35  BaseData::Pointer input;
36  SetPointerParameter("Input", input);
37 
38  // some basedata output
39  BaseData::Pointer output;
40  SetPointerParameter("Output", output);
41  }
42 
43  void NonBlockingAlgorithm::SetPointerParameter(const char *parameter, BaseData *value)
44  {
45  m_ParameterListMutex->Lock();
46  m_Parameters->SetProperty(parameter, SmartPointerProperty::New(value));
47  m_ParameterListMutex->Unlock();
48  }
49 
51  {
52  BaseProperty *value = m_Parameters->GetProperty(parameter);
53  if (value && m_TriggerPropertyConnections.find(parameter) == m_TriggerPropertyConnections.end())
54  {
55  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::Pointer command =
56  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::New();
57  command->SetCallbackFunction(this, &NonBlockingAlgorithm::TriggerParameterModified);
58 
59  m_TriggerPropertyConnections[parameter] = value->AddObserver(itk::ModifiedEvent(), command);
60  }
61  }
62 
64  {
65  auto iter = m_TriggerPropertyConnections.find(parameter);
66 
67  if (iter != m_TriggerPropertyConnections.end())
68  {
69  BaseProperty *value = m_Parameters->GetProperty(parameter);
70 
71  MITK_ERROR(!value) << "NonBlockingAlgorithm::UnDefineTriggerProperty() in bad state." << std::endl;
72  ;
73 
74  value->RemoveObserver(m_TriggerPropertyConnections[parameter]);
75  m_TriggerPropertyConnections.erase(iter);
76  }
77  }
78 
81  {
83  StopAlgorithm();
84  }
85 
87  {
88  if (!ReadyToRun())
89  return; // let algorithm check if all input/parameters are ok
90  if (m_KillRequest)
91  return; // someone wants us to die
92 
93  m_ParameterListMutex->Lock();
94  m_ThreadParameters.m_Algorithm = this;
95  ++m_UpdateRequests;
96  m_ParameterListMutex->Unlock();
97  if (m_ThreadID != -1) // thread already running. But something obviously wants us to recalculate the output
98  {
99  return; // thread already running
100  }
101 
102  // spawn a thread that calls ThreadedUpdateFunction(), and ThreadedUpdateFinished() on us
103  itk::ThreadFunctionType fpointer = &StaticNonBlockingAlgorithmThread;
104  m_ThreadID = m_MultiThreader->SpawnThread(fpointer, &m_ThreadParameters);
105  }
106 
108  {
109  if (m_ThreadID == -1)
110  return; // thread not running
111 
112  m_MultiThreader->TerminateThread(m_ThreadID); // waits for the thread to terminate on its own
113  }
114 
115  // a static function to call a member of NonBlockingAlgorithm from inside an ITK thread
116  ITK_THREAD_RETURN_TYPE NonBlockingAlgorithm::StaticNonBlockingAlgorithmThread(void *param)
117  {
118  // itk::MultiThreader provides an itk::MultiThreader::ThreadInfoStruct as parameter
119  auto *itkmttis = static_cast<itk::MultiThreader::ThreadInfoStruct *>(param);
120 
121  // we need the UserData part of that structure
122  auto *flsp = static_cast<ThreadParameters *>(itkmttis->UserData);
123 
124  NonBlockingAlgorithm::Pointer algorithm = flsp->m_Algorithm;
125  // this UserData tells us, which BubbleTool's method to call
126  if (!algorithm)
127  {
128  return ITK_THREAD_RETURN_VALUE;
129  }
130 
131  algorithm->m_ParameterListMutex->Lock();
132  while (algorithm->m_UpdateRequests > 0)
133  {
134  algorithm->m_UpdateRequests = 0;
135  algorithm->m_ParameterListMutex->Unlock();
136 
137  // actually call the methods that do the work
138  if (algorithm->ThreadedUpdateFunction()) // returns a bool for success/failure
139  {
140  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::Pointer command =
141  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::New();
142  command->SetCallbackFunction(algorithm, &NonBlockingAlgorithm::ThreadedUpdateSuccessful);
144  // algorithm->ThreadedUpdateSuccessful();
145  }
146  else
147  {
148  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::Pointer command =
149  itk::ReceptorMemberCommand<NonBlockingAlgorithm>::New();
150  command->SetCallbackFunction(algorithm, &NonBlockingAlgorithm::ThreadedUpdateFailed);
152  // algorithm->ThreadedUpdateFailed();
153  }
154 
155  algorithm->m_ParameterListMutex->Lock();
156  }
157  algorithm->m_ParameterListMutex->Unlock();
158 
159  return ITK_THREAD_RETURN_VALUE;
160  }
161 
164  {
165  return true; // default is always ready
166  }
167 
169  // called from gui thread
170  void NonBlockingAlgorithm::ThreadedUpdateSuccessful(const itk::EventObject &)
171  {
173 
174  m_ParameterListMutex->Lock();
175  m_ThreadID = -1; // tested before starting
176  m_ParameterListMutex->Unlock();
177  m_ThreadParameters.m_Algorithm = nullptr;
178  }
179 
181  {
182  // notify observers that a result is ready
183  InvokeEvent(ResultAvailable(this));
184  }
185 
186  // called from gui thread
187  void NonBlockingAlgorithm::ThreadedUpdateFailed(const itk::EventObject &)
188  {
190 
191  m_ParameterListMutex->Lock();
192  m_ThreadID = -1; // tested before starting
193  m_ParameterListMutex->Unlock();
194  m_ThreadParameters.m_Algorithm = nullptr; // delete
195  }
196 
198  {
199  // notify observers that something went wrong
200  InvokeEvent(ProcessingError(this));
201  }
202 
203 } // namespace
itk::SmartPointer< NonBlockingAlgorithm > m_Algorithm
Data management class that handles &#39;was created by&#39; relations.
static Pointer New()
Base of all data objects.
Definition: mitkBaseData.h:37
#define MITK_ERROR
Definition: mitkLogMacros.h:20
virtual void Initialize(const NonBlockingAlgorithm *other=nullptr)
DataCollection - Class to facilitate loading/accessing structured data.
WeakPointer< DataStorage > m_DataStorage
Abstract base class for properties.
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.