1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 /*=========================================================================
19 *
20 * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21 *
22 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23 *
24 * For complete copyright, license and disclaimer of warranty information
25 * please refer to the NOTICE file at the top of the ITK source tree.
26 *
27 *=========================================================================*/
28 #include "itkPlatformMultiThreader.h"
29
30 #include "itkObjectFactory.h"
31 #include "itksys/SystemTools.hxx"
32 #include <unistd.h>
33
34 #ifdef __APPLE__
35 #include <sys/types.h>
36 #include <sys/sysctl.h>
37 #endif
38
39 namespace itk
40 {
41 extern "C"
42 {
43 typedef void *( *c_void_cast )(void *);
44 }
45
46 #if !defined ( ITK_LEGACY_REMOVE )
MultipleMethodExecute()47 void PlatformMultiThreader::MultipleMethodExecute()
48 {
49
50 pthread_t process_id[ITK_MAX_THREADS];
51
52 // obey the global maximum number of threads limit
53 if( m_NumberOfWorkUnits > MultiThreaderBase::GetGlobalMaximumNumberOfThreads() )
54 {
55 m_NumberOfWorkUnits = MultiThreaderBase::GetGlobalMaximumNumberOfThreads();
56 }
57 for( ThreadIdType thread_loop = 0; thread_loop < m_NumberOfWorkUnits; ++thread_loop )
58 {
59 if( m_MultipleMethod[thread_loop] == (ThreadFunctionType)nullptr )
60 {
61 itkExceptionMacro(<< "No multiple method set for: " << thread_loop);
62 return;
63 }
64 }
65
66 // Using POSIX threads
67 //
68 // We want to use pthread_create to start m_NumberOfWorkUnits - 1
69 // additional
70 // threads which will be used to call the NumberOfWorkUnits-1 methods
71 // defined in m_MultipleMethods[](). The parent thread
72 // will call m_MultipleMethods[NumberOfWorkUnits-1](). When it is done,
73 // it will wait for all the children to finish.
74 //
75 // First, start up the m_NumberOfWorkUnits-1 processes. Keep track
76 // of their process ids for use later in the pthread_join call
77
78 pthread_attr_t attr;
79
80 pthread_attr_init(&attr);
81 #ifndef __CYGWIN__
82 pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
83 #endif
84 for( ThreadIdType thread_loop = 1; thread_loop < m_NumberOfWorkUnits; ++thread_loop )
85 {
86 m_ThreadInfoArray[thread_loop].UserData =
87 m_MultipleData[thread_loop];
88 m_ThreadInfoArray[thread_loop].NumberOfWorkUnits = m_NumberOfWorkUnits;
89 int threadError = pthread_create( &( process_id[thread_loop] ),
90 &attr, reinterpret_cast<c_void_cast>( m_MultipleMethod[thread_loop] ),
91 ( (void *)( &m_ThreadInfoArray[thread_loop] ) ) );
92 if( threadError != 0 )
93 {
94 itkExceptionMacro(<< "Unable to create a thread. pthread_create() returned "
95 << threadError);
96 }
97 }
98
99 // Now, the parent thread calls the last method itself
100 m_ThreadInfoArray[0].UserData = m_MultipleData[0];
101 m_ThreadInfoArray[0].NumberOfWorkUnits = m_NumberOfWorkUnits;
102 ( m_MultipleMethod[0] )( (void *)( &m_ThreadInfoArray[0] ) );
103 // The parent thread has finished its method - so now it
104 // waits for each of the other processes to exit
105 for( ThreadIdType thread_loop = 1; thread_loop < m_NumberOfWorkUnits; ++thread_loop )
106 {
107 pthread_join(process_id[thread_loop], nullptr);
108 }
109
110 }
111
SpawnThread(ThreadFunctionType f,void * UserData)112 ThreadIdType PlatformMultiThreader::SpawnThread(ThreadFunctionType f, void *UserData)
113 {
114 ThreadIdType id = 0;
115
116 while( id < ITK_MAX_THREADS )
117 {
118 if( !m_SpawnedThreadActiveFlagLock[id] )
119 {
120 m_SpawnedThreadActiveFlagLock[id] = std::make_shared< std::mutex >();
121 }
122 m_SpawnedThreadActiveFlagLock[id]->lock();
123 if( m_SpawnedThreadActiveFlag[id] == 0 )
124 {
125 // We've got a useable thread id, so grab it
126 m_SpawnedThreadActiveFlag[id] = 1;
127 m_SpawnedThreadActiveFlagLock[id]->unlock();
128 break;
129 }
130 m_SpawnedThreadActiveFlagLock[id]->unlock();
131
132 id++;
133 }
134
135 if( id >= ITK_MAX_THREADS )
136 {
137 itkExceptionMacro(<< "You have too many active threads!");
138 }
139
140 m_SpawnedThreadInfoArray[id].UserData = UserData;
141 m_SpawnedThreadInfoArray[id].NumberOfWorkUnits = 1;
142 m_SpawnedThreadInfoArray[id].ActiveFlag = &m_SpawnedThreadActiveFlag[id];
143 m_SpawnedThreadInfoArray[id].ActiveFlagLock = m_SpawnedThreadActiveFlagLock[id];
144
145 pthread_attr_t attr;
146
147 pthread_attr_init(&attr);
148 #ifndef __CYGWIN__
149 pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
150 #endif
151
152 int threadError = pthread_create( &( m_SpawnedThreadProcessID[id] ),
153 &attr, reinterpret_cast<c_void_cast>( f ),
154 ( (void *)( &m_SpawnedThreadInfoArray[id] ) ) );
155 if( threadError != 0 )
156 {
157 itkExceptionMacro(<< "Unable to create a thread. pthread_create() returned "
158 << threadError);
159 }
160
161 return id;
162 }
163
TerminateThread(ThreadIdType WorkUnitID)164 void PlatformMultiThreader::TerminateThread(ThreadIdType WorkUnitID)
165 {
166 if( !m_SpawnedThreadActiveFlag[WorkUnitID] )
167 {
168 return;
169 }
170
171 m_SpawnedThreadActiveFlagLock[WorkUnitID]->lock();
172 m_SpawnedThreadActiveFlag[WorkUnitID] = 0;
173 m_SpawnedThreadActiveFlagLock[WorkUnitID]->unlock();
174
175 pthread_join(m_SpawnedThreadProcessID[WorkUnitID], nullptr);
176
177 m_SpawnedThreadActiveFlagLock[WorkUnitID] = nullptr;
178 m_SpawnedThreadActiveFlagLock[WorkUnitID] = nullptr;
179 }
180 #endif
181
182 void
183 PlatformMultiThreader
SpawnWaitForSingleMethodThread(ThreadProcessIdType threadHandle)184 ::SpawnWaitForSingleMethodThread(ThreadProcessIdType threadHandle)
185 {
186 // Using POSIX threads
187 if ( pthread_join(threadHandle, nullptr) )
188 {
189 itkExceptionMacro(<< "Unable to join thread.");
190 }
191 }
192
193 ThreadProcessIdType
194 PlatformMultiThreader
SpawnDispatchSingleMethodThread(PlatformMultiThreader::WorkUnitInfo * threadInfo)195 ::SpawnDispatchSingleMethodThread(PlatformMultiThreader::WorkUnitInfo *threadInfo)
196 {
197 // Using POSIX threads
198 pthread_attr_t attr;
199 pthread_t threadHandle;
200
201 pthread_attr_init(&attr);
202 #if !defined( __CYGWIN__ )
203 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
204 #endif
205
206 int threadError;
207 threadError =
208 pthread_create( &threadHandle, &attr, reinterpret_cast< c_void_cast >( this->SingleMethodProxy ),
209 reinterpret_cast< void * >( threadInfo ) );
210 if ( threadError != 0 )
211 {
212 itkExceptionMacro(<< "Unable to create a thread. pthread_create() returned "
213 << threadError);
214 }
215 return threadHandle;
216 }
217
218 } // end namespace itk
219