![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 #ifndef __TBB_parallel_for_H 00030 #define __TBB_parallel_for_H 00031 00032 #include "task.h" 00033 #include "partitioner.h" 00034 #include "blocked_range.h" 00035 #include <new> 00036 #include "tbb_exception.h" 00037 00038 namespace tbb { 00039 00041 namespace internal { 00042 00044 00045 template<typename Range, typename Body, typename Partitioner> 00046 class start_for: public task { 00047 Range my_range; 00048 const Body my_body; 00049 typename Partitioner::partition_type my_partition; 00050 /*override*/ task* execute(); 00051 00053 start_for( const Range& range, const Body& body, Partitioner& partitioner ) : 00054 my_range(range), 00055 my_body(body), 00056 my_partition(partitioner) 00057 { 00058 } 00060 00061 start_for( start_for& parent_, split ) : 00062 my_range(parent_.my_range,split()), 00063 my_body(parent_.my_body), 00064 my_partition(parent_.my_partition,split()) 00065 { 00066 my_partition.set_affinity(*this); 00067 } 00069 /*override*/ void note_affinity( affinity_id id ) { 00070 my_partition.note_affinity( id ); 00071 } 00072 public: 00073 static void run( const Range& range, const Body& body, const Partitioner& partitioner ) { 00074 if( !range.empty() ) { 00075 #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP 00076 start_for& a = *new(task::allocate_root()) start_for(range,body,const_cast<Partitioner&>(partitioner)); 00077 #else 00078 // Bound context prevents exceptions from body to affect nesting or sibling algorithms, 00079 // and allows users to handle exceptions safely by wrapping parallel_for in the try-block. 00080 task_group_context context; 00081 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner)); 00082 #endif /* __TBB_TASK_GROUP_CONTEXT && !TBB_JOIN_OUTER_TASK_GROUP */ 00083 task::spawn_root_and_wait(a); 00084 } 00085 } 00086 #if __TBB_TASK_GROUP_CONTEXT 00087 static void run( const Range& range, const Body& body, const Partitioner& partitioner, task_group_context& context ) { 00088 if( !range.empty() ) { 00089 start_for& a = *new(task::allocate_root(context)) start_for(range,body,const_cast<Partitioner&>(partitioner)); 00090 task::spawn_root_and_wait(a); 00091 } 00092 } 00093 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00094 }; 00095 00096 template<typename Range, typename Body, typename Partitioner> 00097 task* start_for<Range,Body,Partitioner>::execute() { 00098 if( !my_range.is_divisible() || my_partition.should_execute_range(*this) ) { 00099 my_body( my_range ); 00100 return my_partition.continue_after_execute_range(); 00101 } else { 00102 empty_task& c = *new( this->allocate_continuation() ) empty_task; 00103 recycle_as_child_of(c); 00104 c.set_ref_count(2); 00105 bool delay = my_partition.decide_whether_to_delay(); 00106 start_for& b = *new( c.allocate_child() ) start_for(*this,split()); 00107 my_partition.spawn_or_delay(delay,b); 00108 return this; 00109 } 00110 } 00111 } // namespace internal 00113 00114 00115 // Requirements on Range concept are documented in blocked_range.h 00116 00127 00129 00130 template<typename Range, typename Body> 00131 void parallel_for( const Range& range, const Body& body ) { 00132 internal::start_for<Range,Body,__TBB_DEFAULT_PARTITIONER>::run(range,body,__TBB_DEFAULT_PARTITIONER()); 00133 } 00134 00136 00137 template<typename Range, typename Body> 00138 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) { 00139 internal::start_for<Range,Body,simple_partitioner>::run(range,body,partitioner); 00140 } 00141 00143 00144 template<typename Range, typename Body> 00145 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) { 00146 internal::start_for<Range,Body,auto_partitioner>::run(range,body,partitioner); 00147 } 00148 00150 00151 template<typename Range, typename Body> 00152 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) { 00153 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner); 00154 } 00155 00156 #if __TBB_TASK_GROUP_CONTEXT 00157 00158 00159 template<typename Range, typename Body> 00160 void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner, task_group_context& context ) { 00161 internal::start_for<Range,Body,simple_partitioner>::run(range, body, partitioner, context); 00162 } 00163 00165 00166 template<typename Range, typename Body> 00167 void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner, task_group_context& context ) { 00168 internal::start_for<Range,Body,auto_partitioner>::run(range, body, partitioner, context); 00169 } 00170 00172 00173 template<typename Range, typename Body> 00174 void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner, task_group_context& context ) { 00175 internal::start_for<Range,Body,affinity_partitioner>::run(range,body,partitioner, context); 00176 } 00177 #endif /* __TBB_TASK_GROUP_CONTEXT */ 00178 00179 00181 namespace internal { 00183 template<typename Function, typename Index> 00184 class parallel_for_body : internal::no_assign { 00185 const Function &my_func; 00186 const Index my_begin; 00187 const Index my_step; 00188 public: 00189 parallel_for_body( const Function& _func, Index& _begin, Index& _step) 00190 : my_func(_func), my_begin(_begin), my_step(_step) {} 00191 00192 void operator()( tbb::blocked_range<Index>& r ) const { 00193 for( Index i = r.begin(), k = my_begin + i * my_step; i < r.end(); i++, k = k + my_step) 00194 my_func( k ); 00195 } 00196 }; 00197 } // namespace internal 00199 00200 namespace strict_ppl { 00201 00203 00204 template <typename Index, typename Function> 00205 void parallel_for(Index first, Index last, Index step, const Function& f) { 00206 tbb::task_group_context context; 00207 parallel_for(first, last, step, f, context); 00208 } 00209 template <typename Index, typename Function> 00210 void parallel_for(Index first, Index last, Index step, const Function& f, tbb::task_group_context &context) { 00211 if (step <= 0 ) 00212 internal::throw_exception(internal::eid_nonpositive_step); // throws std::invalid_argument 00213 else if (last > first) { 00214 // Above "else" is necessary to prevent "potential divide by zero" warning 00215 Index end = (last - first) / step; 00216 if (first + end * step < last) end++; 00217 tbb::blocked_range<Index> range(static_cast<Index>(0), end); 00218 internal::parallel_for_body<Function, Index> body(f, first, step); 00219 tbb::parallel_for(range, body, tbb::auto_partitioner(), context); 00220 } 00221 } 00223 template <typename Index, typename Function> 00224 void parallel_for(Index first, Index last, const Function& f) { 00225 tbb::task_group_context context; 00226 parallel_for(first, last, static_cast<Index>(1), f, context); 00227 } 00228 template <typename Index, typename Function> 00229 void parallel_for(Index first, Index last, const Function& f, tbb::task_group_context &context) { 00230 parallel_for(first, last, static_cast<Index>(1), f, context); 00231 } 00232 00234 00235 } // namespace strict_ppl 00236 00237 using strict_ppl::parallel_for; 00238 00239 } // namespace tbb 00240 00241 #endif /* __TBB_parallel_for_H */ 00242
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.