Josh Cooper
, ,
No Comments


There you are designing a parallel algorithm, and then it occurs to you: How do I return information to the main thread from a child thread?

If you’ve skimmed through half of The C++ Programming Language (4th Edition) by Bjarne Stroustrup like I have, you may recall a section about futures and promises which are related to threads.

Well those are exactly what we need, although I am sure you could create a custom solution. Like perhaps locking and inserting your data into an external container. Perhaps you prefer a standard C++ answer to your problems though? This way it makes sense and you need less comments.

My case was that I wished to learn the “proper” way to do it, and boy did I have a time learning.

Let’s get to the bottom line.. std::promise and std::future are the “proper” way to extract processed data from a thread. So how does one do that?

Well here is an excerpt from my WordSearch project.

	struct ThreadResults //Might as well package these together
	{
		std::future<std::vector<FoundWord>> future;
		std::promise<std::vector<FoundWord>> promise;
	};

	using std::thread;
	using Task = std::pair < thread*, ThreadResults* >; //This is practically a comment already
	std::vector<Task> Task_List;
	
	//We need threads to extract from

	for ( auto search_word_list : Search_Words )
	{ //Our Puzzle Words are grouped by size

		for ( int i = search_word_list.first; i <= largest_search_area; ++i )
		{ //search_word_list.first is the size of words in the list
			//We only want search areas big enough for the word to fit in

			if ( Search_Areas.find( i ) != Search_Areas.end() )
			{
				std::vector<WordBoxWord>& search_area_list = Search_Areas[i];
				ThreadResults* shared_state = new ThreadResults;
				//You need to associate the promise to the future. That is why promise::get_future() exists
				shared_state->future = shared_state->promise.get_future();

				//This is the part that got me. You need to std::move( promise ) in order to pass it to a new thread.
				//I tried passing by reference. Pointer.. you name it. This is how you do it!
				std::thread *T = new std::thread( SearchAlg, std::move( shared_state->promise ), search_word_list.second, std::ref( search_area_list ) );
				Task_List.push_back( std::make_pair( T, shared_state ) );
			}
		}
	}

	//While there are tasks we haven't checked on
	while ( Task_List.size() != 0 )
	{
		auto task = Task_List.begin();
		task->first->join(); // These are threads we're dealing with.. gotta join them back
		auto results = task->second->future.get(); // EXTRACTION!! WOO

		for ( auto word_iterator = results.begin(); word_iterator != results.end(); ++word_iterator )
		{
			this->Words_Found.push_back( *word_iterator );
		}
		delete task->first;// thread
		delete task->second; // data

		//Task data is saved and pointers deleted, erase the task
		Task_List.erase( task );
	}