Initial commit: Final state of the master project
This commit is contained in:
186
Research/inc/tbb/parallel_while.h
Normal file
186
Research/inc/tbb/parallel_while.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
Copyright 2005-2015 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 */
|
||||
Reference in New Issue
Block a user