C++11's async Template
When To Use async
In his C++11 FAQ, Bjarne Stroustroup has this to say about async:
...don't even think of using async() to launch tasks that do I/O, manipulate mutexes, or in other ways interact with other tasks. The idea behind async() is the same as the idea behind the range-for statement: Provide a simple way to handle the simplest, rather common, case and leave the more complex examples to the fully general mechanism.
I'm not sure I agree with this disclaimer. The async function is in no way a second-class citizen when it comes to launching threads. It simply lowers the barriers to using threads by providing a very nice mechanism for launching them and retrieving their return values.
You can see that in my example I use a mutex to guard access to a data structure. This is not made more dangerous by using async to launch my thread — I use the mutex exactly as I would if I had launched my threads using the thread class.
If your compiler supports async, I say use it!
Does Your Compiler Support async?
No doubt these new C++11 features are quite cool, but in order to use them, your compiler has to support them. Does yours?
It's a little hard to read the status of async by browsing the g++ or the Visual C++ 11 beta charts. Regardless of what they may say, this program does build and run properly with g++ 4.7 and the Visual C++ 11 beta.
Updating to g++ 4.7 on your Linux system can be somewhat tricky. Ideally, you would like to find a prebuilt version of the compiler that will work with your distribution. As an example, I was able to easily update my Ubuntu system with the instructions found here. Visual C++ 11 is here. Visual C++ 11 is available to all for free - installing alongside other versions of Vis>available to all for free — installing alongside other versions of Visual C++ seems to work fine.
A little extra work maybe, but really, you shoulder be knee-deep in C++11 by now. This is modern C++.
WordSearch.cpp Source
You can download a copy of sowpods.txt here. The full source for WordSearch.cpp is here:
//
// WordSearch.cpp
//
// When building with g++ 4.7 or later, use this command line:
//
// g++ -pthread --std=c++0x
//
#include <fstream>
#include <iostream>
#include <string>
#include <deque>
#include <vector>
#include <future>
#include <mutex>
#include <functional>
using namespace std;
std::mutex m;
inline bool match( const std::string &pattern, std::string word )
{
if ( pattern.size() != word.size() )
return false;
for ( size_t i = 0 ; i < pattern.size() ; i++ )
if ( pattern[ i ] != '.' && pattern[ i ] != word[ i ] )
return false;
return true;
}
vector<string> find_matches( string pattern, deque<string> &backlog )
{
vector<string> results;
for ( ; ; ) {
m.lock();
if ( backlog.size() == 0 ) {
m.unlock();
return results;
}
string word = backlog.front();
backlog.pop_front();
m.unlock();
if ( match( pattern, word ) )
results.push_back( word );
}
}
template<class ASYNC>
void print_results( ASYNC &f, string &pattern, int threadno )
{
vector<string> words = f.get();
cerr << "Found " << words.size()
<< " matches for " << pattern
<< " in thread " << threadno
<< endl;
for ( auto s : words )
cout << s << "\n";
}
int main( int argc, char *argv[] )
{
if ( argc < 2 ) {
cerr << "Usage: WordSearch match-expression\n\n"
"match-expression contains lower case letters and periods.\n"
"The periods will match any character\n";
return -1;
}
string pattern = argv[ 1 ];
//
// Load the words into the deque
//
ifstream f( "sowpods.txt" );
if ( !f ) {
cerr << "Cannot open sowpods.txt in the current directory\n";
return -1;
}
string word;
deque<string> backlog;
while ( f >> word )
backlog.push_back( word );
//
// Now process the words and print the results
//
auto f1 = async( launch::async, find_matches, pattern, ref(backlog) );
auto f2 = async( launch::async, find_matches, pattern, ref(backlog) );
auto f3 = async( launch::async, find_matches, pattern, ref(backlog) );
print_results( f1, pattern, 1 );
print_results( f2, pattern, 2 );
print_results( f3, pattern, 3 );
return 0;
}

