Codebase list cppad / upstream/2015.00.00.7 doc / team_bthread.cpp.xml
upstream/2015.00.00.7

Tree @upstream/2015.00.00.7 (Download .tar.gz)

team_bthread.cpp.xml @upstream/2015.00.00.7raw · history · blame

<?xml version='1.0'?>
<html xmlns='http://www.w3.org/1999/xhtml'
      xmlns:math='http://www.w3.org/1998/Math/MathML'
>
<head>
<title>Boost Thread Implementation of a Team of AD Threads</title>
<meta http-equiv='Content-Type' content='text/html' charset='utf-8'/>
<meta name="description" id="description" content="Boost Thread Implementation of a Team of AD Threads"/>
<meta name="keywords" id="keywords" content=" bthread Ad team boost thread implementation of a ad threads "/>
<style type='text/css'>
body { color : black }
body { background-color : white }
A:link { color : blue }
A:visited { color : purple }
A:active { color : purple }
</style>
<script type='text/javascript' language='JavaScript' src='_team_bthread.cpp_xml.js'>
</script>
</head>
<body>
<table><tr>
<td>
<a href="http://www.coin-or.org/CppAD/" target="_top"><img border="0" src="_image.gif"/></a>
</td>
<td><a href="team_openmp.cpp.xml" target="_top">Prev</a>
</td><td><a href="team_pthread.cpp.xml" target="_top">Next</a>
</td><td>
<select onchange='choose_across0(this)'>
<option>Index-&gt;</option>
<option>contents</option>
<option>reference</option>
<option>index</option>
<option>search</option>
<option>external</option>
</select>
</td>
<td>
<select onchange='choose_up0(this)'>
<option>Up-&gt;</option>
<option>CppAD</option>
<option>multi_thread</option>
<option>thread_test.cpp</option>
<option>team_thread.hpp</option>
<option>team_bthread.cpp</option>
</select>
</td>
<td>
<select onchange='choose_down3(this)'>
<option>multi_thread-&gt;</option>
<option>parallel_ad</option>
<option>thread_test.cpp</option>
</select>
</td>
<td>
<select onchange='choose_down2(this)'>
<option>thread_test.cpp-&gt;</option>
<option>a11c_openmp.cpp</option>
<option>a11c_bthread.cpp</option>
<option>a11c_pthread.cpp</option>
<option>simple_ad_openmp.cpp</option>
<option>simple_ad_bthread.cpp</option>
<option>simple_ad_pthread.cpp</option>
<option>team_example.cpp</option>
<option>harmonic.cpp</option>
<option>multi_newton.cpp</option>
<option>team_thread.hpp</option>
</select>
</td>
<td>
<select onchange='choose_down1(this)'>
<option>team_thread.hpp-&gt;</option>
<option>team_openmp.cpp</option>
<option>team_bthread.cpp</option>
<option>team_pthread.cpp</option>
</select>
</td>
<td>team_bthread.cpp</td>
<td>Headings</td>
</tr></table><br/>







<center><b><big><big>Boost Thread Implementation of a Team of AD Threads</big></big></b></center>
See <a href="team_thread.hpp.xml" target="_top"><span style='white-space: nowrap'>team_thread.hpp</span></a>
 for this routines specifications.

<code><font color="blue">
<pre style='display:inline'> 
# include &lt;boost/thread.hpp&gt;
# include &lt;cppad/cppad.hpp&gt;
# include &quot;../team_thread.hpp&quot;
# define MAX_NUMBER_THREADS 48

namespace {
	using CppAD::thread_alloc;

	// number of threads in the team
	size_t num_threads_ = 1; 

	// no need to cleanup up thread specific data 
	void cleanup(size_t*)
	{	return; }

	// thread specific pointer the thread number (initialize as null)
	boost::thread_specific_ptr&lt;size_t&gt; thread_num_ptr_(cleanup);

	// type of the job currently being done by each thread
	enum thread_job_t { init_enum, work_enum, join_enum } thread_job_;

	// barrier used to wait for other threads to finish work
	boost::barrier* wait_for_work_ = CPPAD_NULL;

	// barrier used to wait for master thread to set next job
	boost::barrier* wait_for_job_ = CPPAD_NULL;

	// Are we in sequential mode; i.e., other threads are waiting for
	// master thread to set up next job ?
	bool sequential_execution_ = true;

	// structure with information for one thread
	typedef struct {
		// The thread
		boost::thread*       bthread;
		// CppAD thread number as global (pointed to by thread_num_ptr_)
		size_t               thread_num;
		// true if no error for this thread, false otherwise.
		bool                 ok;
	} thread_one_t;

	// vector with information for all threads
	thread_one_t thread_all_[MAX_NUMBER_THREADS];

	// pointer to function that does the work for one thread
	void (* worker_)(void) = CPPAD_NULL;

	// ---------------------------------------------------------------------
	// in_parallel()
	bool in_parallel(void)
	{	return ! sequential_execution_; }

	// ---------------------------------------------------------------------
	// thread_number()
	size_t thread_number(void)
	{	// return thread_all_[thread_num].thread_num
		return *thread_num_ptr_.get();
	}
	// --------------------------------------------------------------------
	// function that gets called by boost thread constructor
	void thread_work(size_t thread_num)
	{	bool ok = wait_for_work_ != CPPAD_NULL;
		ok     &amp;= wait_for_job_  != CPPAD_NULL;
		ok     &amp;= thread_num     != 0;

		// thread specific storage of thread number for this thread
		thread_num_ptr_.reset(&amp; thread_all_[thread_num].thread_num );

		while( true )
		{
			// Use wait_for_jog_ to give master time in sequential mode
			// (so it can change global information like thread_job_)
			wait_for_job_-&gt;wait();

			// case where we are terminating this thread (no more work)
			if( thread_job_ == join_enum)
				break;

			// only other case once wait_for_job_ has been completed (so far)
			ok &amp;= thread_job_ == work_enum;
			worker_();

			// Use wait_for_work_ to inform master that our work is done and
			// that this thread will not use global infromation until
			// passing its barrier wait_for_job_ above.
			wait_for_work_-&gt;wait();

		}
		thread_all_[thread_num].ok &amp;= ok;
		return;
	}
}

bool team_create(size_t num_threads)
{	bool ok = true;;

	if( num_threads &gt; MAX_NUMBER_THREADS )
	{	std::cerr &lt;&lt; &quot;team_create: num_threads greater than &quot;;
		std::cerr &lt;&lt; MAX_NUMBER_THREADS &lt;&lt; std::endl;
		exit(1);
	}
	// check that we currently do not have multiple threads running
	ok  = num_threads_ == 1;
	ok &amp;= wait_for_work_ == CPPAD_NULL;
	ok &amp;= wait_for_job_  == CPPAD_NULL;
	ok &amp;= sequential_execution_;

	size_t thread_num;
	for(thread_num = 0; thread_num &lt; num_threads; thread_num++)
	{	// Each thread gets a pointer to its version of this thread_num
		// so it knows which section of thread_all it is working with
		thread_all_[thread_num].thread_num = thread_num;

		// initialize
		thread_all_[thread_num].ok = true;
		thread_all_[0].bthread     = CPPAD_NULL;
	}
	// Finish setup of thread_all_ for this thread
	thread_num_ptr_.reset(&amp; thread_all_[0].thread_num);

	// Now that thread_number() has necessary information for the case
	// num_threads_ == 1, and while still in sequential mode,
	// call setup for using CppAD::<a href="ad.xml" target="_top">AD</a>&lt;double&gt; in parallel mode.
	thread_alloc::parallel_setup(num_threads, in_parallel, thread_number);
	thread_alloc::hold_memory(true);
	CppAD::parallel_ad&lt;double&gt;();

	// now change num_threads_ to its final value.
	num_threads_ = num_threads;

	// initialize two barriers, one for work done, one for new job ready
	wait_for_work_ = new boost::barrier(num_threads); 
	wait_for_job_  = new boost::barrier(num_threads); 
	
	// initial job for the threads
	thread_job_           = init_enum;
	if( num_threads &gt; 1 )
		sequential_execution_ = false;

	// This master thread is already running, we need to create
	// num_threads - 1 more threads
	for(thread_num = 1; thread_num &lt; num_threads; thread_num++)
	{	// Create the thread with thread number equal to thread_num
		thread_all_[thread_num].bthread = 
			new boost::thread(thread_work, thread_num);
	}

	// Current state is other threads are at wait_for_job_.
	// This master thread (thread zero) has not completed wait_for_job_
	sequential_execution_ = true;
	return ok;
}

bool team_work(void worker(void))
{
	// Current state is other threads are at wait_for_job_.
	// This master thread (thread zero) has not completed wait_for_job_
	bool ok = sequential_execution_;
	ok     &amp;= thread_number() == 0;
	ok     &amp;= wait_for_work_  != CPPAD_NULL;
	ok     &amp;= wait_for_job_   != CPPAD_NULL;

	// set global version of this work routine
	worker_ = worker;

	// set the new job that other threads are waiting for
	thread_job_ = work_enum;

	// Enter parallel exectuion when master thread calls wait_for_job_ 
	if( num_threads_ &gt; 1 )
		sequential_execution_ = false;
	wait_for_job_-&gt;wait();

	// Now do the work in this thread and then wait
	// until all threads have completed wait_for_work_
	worker();
	wait_for_work_-&gt;wait();

	// Current state is other threads are at wait_for_job_.
	// This master thread (thread zero) has not completed wait_for_job_
	sequential_execution_ = true;

	size_t thread_num;
	for(thread_num = 0; thread_num &lt; num_threads_; thread_num++)
		ok &amp;= thread_all_[thread_num].ok;
	return ok;
}

bool team_destroy(void)
{	// Current state is other threads are at wait_for_job_.
	// This master thread (thread zero) has not completed wait_for_job_
	bool ok = sequential_execution_;
	ok     &amp;= thread_number() == 0;
	ok     &amp;= wait_for_work_ != CPPAD_NULL;
	ok     &amp;= wait_for_job_  != CPPAD_NULL;

	// set the new job that other threads are waiting for
	thread_job_ = join_enum;

	// enter parallel exectuion soon as master thread completes wait_for_job_ 
	if( num_threads_ &gt; 1 )
			sequential_execution_ = false;
	wait_for_job_-&gt;wait();

	// now wait for the other threads to be destroyed
	size_t thread_num;
	ok &amp;= thread_all_[0].bthread == CPPAD_NULL;
	for(thread_num = 1; thread_num &lt; num_threads_; thread_num++)
	{	thread_all_[thread_num].bthread-&gt;join();
		delete thread_all_[thread_num].bthread;
		thread_all_[thread_num].bthread = CPPAD_NULL;
	}
	// now we are down to just the master thread (thread zero) 
	sequential_execution_ = true;

	// destroy wait_for_work_
	delete wait_for_work_;
	wait_for_work_ = CPPAD_NULL;

	// destroy wait_for_job_
	delete wait_for_job_;
	wait_for_job_ = CPPAD_NULL;

	// check ok before changing num_threads_
	for(thread_num = 0; thread_num &lt; num_threads_; thread_num++)
		ok &amp;= thread_all_[thread_num].ok;

	// now inform CppAD that there is only one thread
	num_threads_ = 1;
	thread_alloc::parallel_setup(num_threads_, CPPAD_NULL, CPPAD_NULL);
	thread_alloc::hold_memory(false);
	CppAD::parallel_ad&lt;double&gt;();

	return ok;
}

const char* team_name(void)
{	return &quot;bthread&quot;; }
</pre>

</font></code>


<hr/>Input File: multi_thread/bthread/team_bthread.cpp

</body>
</html>