You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							194 lines
						
					
					
						
							6.6 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							194 lines
						
					
					
						
							6.6 KiB
						
					
					
				
								/*
							 | 
						|
								    Copyright 2005-2013 Intel Corporation.  All Rights Reserved.
							 | 
						|
								
							 | 
						|
								    This file is part of Threading Building Blocks.
							 | 
						|
								
							 | 
						|
								    Threading Building Blocks is free software; you can redistribute it
							 | 
						|
								    and/or modify it under the terms of the GNU General Public License
							 | 
						|
								    version 2 as published by the Free Software Foundation.
							 | 
						|
								
							 | 
						|
								    Threading Building Blocks is distributed in the hope that it will be
							 | 
						|
								    useful, but WITHOUT ANY WARRANTY; without even the implied warranty
							 | 
						|
								    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								    GNU General Public License for more details.
							 | 
						|
								
							 | 
						|
								    You should have received a copy of the GNU General Public License
							 | 
						|
								    along with Threading Building Blocks; if not, write to the Free Software
							 | 
						|
								    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
							 | 
						|
								
							 | 
						|
								    As a special exception, you may use this file as part of a free software
							 | 
						|
								    library without restriction.  Specifically, if other files instantiate
							 | 
						|
								    templates or use macros or inline functions from this file, or you compile
							 | 
						|
								    this file and link it with other files to produce an executable, this
							 | 
						|
								    file does not by itself cause the resulting executable to be covered by
							 | 
						|
								    the GNU General Public License.  This exception does not however
							 | 
						|
								    invalidate any other reasons why the executable file might be covered by
							 | 
						|
								    the GNU General Public License.
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								#ifndef __TBB_parallel_while
							 | 
						|
								#define __TBB_parallel_while
							 | 
						|
								
							 | 
						|
								#include "task.h"
							 | 
						|
								#include <new>
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								template<typename Body>
							 | 
						|
								class parallel_while;
							 | 
						|
								
							 | 
						|
								//! @cond INTERNAL
							 | 
						|
								namespace internal {
							 | 
						|
								
							 | 
						|
								    template<typename Stream, typename Body> class while_task;
							 | 
						|
								
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Executes one iteration of a while.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Body>
							 | 
						|
								    class while_iteration_task: public task {
							 | 
						|
								        const Body& my_body;
							 | 
						|
								        typename Body::argument_type my_value;
							 | 
						|
								        /*override*/ task* execute() {
							 | 
						|
								            my_body(my_value); 
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								        while_iteration_task( const typename Body::argument_type& value, const Body& body ) : 
							 | 
						|
								            my_body(body), my_value(value)
							 | 
						|
								        {}
							 | 
						|
								        template<typename Body_> friend class while_group_task;
							 | 
						|
								        friend class tbb::parallel_while<Body>;
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    //! For internal use only
							 | 
						|
								    /** Unpacks a block of iterations.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Body>
							 | 
						|
								    class while_group_task: public task {
							 | 
						|
								        static const size_t max_arg_size = 4;         
							 | 
						|
								        const Body& my_body;
							 | 
						|
								        size_t size;
							 | 
						|
								        typename Body::argument_type my_arg[max_arg_size];
							 | 
						|
								        while_group_task( const Body& body ) : my_body(body), size(0) {} 
							 | 
						|
								        /*override*/ task* execute() {
							 | 
						|
								            typedef while_iteration_task<Body> iteration_type;
							 | 
						|
								            __TBB_ASSERT( size>0, NULL );
							 | 
						|
								            task_list list;
							 | 
						|
								            task* t; 
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            for(;;) {
							 | 
						|
								                t = new( allocate_child() ) iteration_type(my_arg[k],my_body); 
							 | 
						|
								                if( ++k==size ) break;
							 | 
						|
								                list.push_back(*t);
							 | 
						|
								            }
							 | 
						|
								            set_ref_count(int(k+1));
							 | 
						|
								            spawn(list);
							 | 
						|
								            spawn_and_wait_for_all(*t);
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								        template<typename Stream, typename Body_> friend class while_task;
							 | 
						|
								    };
							 | 
						|
								    
							 | 
						|
								    //! For internal use only.
							 | 
						|
								    /** Gets block of iterations from a stream and packages them into a while_group_task.
							 | 
						|
								        @ingroup algorithms */
							 | 
						|
								    template<typename Stream, typename Body>
							 | 
						|
								    class while_task: public task {
							 | 
						|
								        Stream& my_stream;
							 | 
						|
								        const Body& my_body;
							 | 
						|
								        empty_task& my_barrier;
							 | 
						|
								        /*override*/ task* execute() {
							 | 
						|
								            typedef while_group_task<Body> block_type;
							 | 
						|
								            block_type& t = *new( allocate_additional_child_of(my_barrier) ) block_type(my_body);
							 | 
						|
								            size_t k=0; 
							 | 
						|
								            while( my_stream.pop_if_present(t.my_arg[k]) ) {
							 | 
						|
								                if( ++k==block_type::max_arg_size ) {
							 | 
						|
								                    // There might be more iterations.
							 | 
						|
								                    recycle_to_reexecute();
							 | 
						|
								                    break;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            if( k==0 ) {
							 | 
						|
								                destroy(t);
							 | 
						|
								                return NULL;
							 | 
						|
								            } else {
							 | 
						|
								                t.size = k;
							 | 
						|
								                return &t;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        while_task( Stream& stream, const Body& body, empty_task& barrier ) : 
							 | 
						|
								            my_stream(stream),
							 | 
						|
								            my_body(body),
							 | 
						|
								            my_barrier(barrier)
							 | 
						|
								        {} 
							 | 
						|
								        friend class tbb::parallel_while<Body>;
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								} // namespace internal
							 | 
						|
								//! @endcond
							 | 
						|
								
							 | 
						|
								//! Parallel iteration over a stream, with optional addition of more work.
							 | 
						|
								/** The Body b has the requirement: \n
							 | 
						|
								        "b(v)"                      \n
							 | 
						|
								        "b.argument_type"           \n
							 | 
						|
								    where v is an argument_type
							 | 
						|
								    @ingroup algorithms */
							 | 
						|
								template<typename Body>
							 | 
						|
								class parallel_while: internal::no_copy {
							 | 
						|
								public:
							 | 
						|
								    //! Construct empty non-running parallel while.
							 | 
						|
								    parallel_while() : my_body(NULL), my_barrier(NULL) {}
							 | 
						|
								
							 | 
						|
								    //! Destructor cleans up data members before returning.
							 | 
						|
								    ~parallel_while() {
							 | 
						|
								        if( my_barrier ) {
							 | 
						|
								            my_barrier->destroy(*my_barrier);    
							 | 
						|
								            my_barrier = NULL;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Type of items
							 | 
						|
								    typedef typename Body::argument_type value_type;
							 | 
						|
								
							 | 
						|
								    //! Apply body.apply to each item in the stream.
							 | 
						|
								    /** A Stream s has the requirements \n
							 | 
						|
								         "S::value_type"                \n
							 | 
						|
								         "s.pop_if_present(value) is convertible to bool */
							 | 
						|
								    template<typename Stream>
							 | 
						|
								    void run( Stream& stream, const Body& body );
							 | 
						|
								
							 | 
						|
								    //! Add a work item while running.
							 | 
						|
								    /** Should be executed only by body.apply or a thread spawned therefrom. */
							 | 
						|
								    void add( const value_type& item );
							 | 
						|
								
							 | 
						|
								private:
							 | 
						|
								    const Body* my_body;
							 | 
						|
								    empty_task* my_barrier;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								template<typename Body>
							 | 
						|
								template<typename Stream>
							 | 
						|
								void parallel_while<Body>::run( Stream& stream, const Body& body ) {
							 | 
						|
								    using namespace internal;
							 | 
						|
								    empty_task& barrier = *new( task::allocate_root() ) empty_task();
							 | 
						|
								    my_body = &body;
							 | 
						|
								    my_barrier = &barrier;
							 | 
						|
								    my_barrier->set_ref_count(2);
							 | 
						|
								    while_task<Stream,Body>& w = *new( my_barrier->allocate_child() ) while_task<Stream,Body>( stream, body, barrier );
							 | 
						|
								    my_barrier->spawn_and_wait_for_all(w);
							 | 
						|
								    my_barrier->destroy(*my_barrier);
							 | 
						|
								    my_barrier = NULL;
							 | 
						|
								    my_body = NULL;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								template<typename Body>
							 | 
						|
								void parallel_while<Body>::add( const value_type& item ) {
							 | 
						|
								    __TBB_ASSERT(my_barrier,"attempt to add to parallel_while that is not running");
							 | 
						|
								    typedef internal::while_iteration_task<Body> iteration_type;
							 | 
						|
								    iteration_type& i = *new( task::allocate_additional_child_of(*my_barrier) ) iteration_type(item,*my_body);
							 | 
						|
								    task::self().spawn( i );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								} // namespace 
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_parallel_while */
							 |