Channels ▼


Task-Based Programming in Windows

There and Back Again

The plumbing for passing object instances around and invoking methods asynchronously are supplied by a pair of template classes: AsyncStateT and AsyncMethodT. Listing Three is simple class declaration:

Listing Three: The AsyncStateT class.
class MyAsyncClass: public AsyncStateT<MyAsyncClass>


	    typedef AsyncMethodT<MyAsyncClass> Method;
	    typedef AsyncStateT<MyAsyncClass> State;


	    unsigned Initialize();
	    unsigned Step();
	    unsigned Finalize();	
	    unsigned Report();	

	    unsigned _counter;

AsyncStateT implements an instance of IAsyncState, which is the interface required by IO::Queue::Post(). But before we can hand off an instance of our new class, we need to setup the method to be invoked on the worker thread. This is handled in the constructor as follows:

	State::SetMethod(new Method(&MyAsyncClass::Initialize));	

State::SetMethod indicates the current method to be executed. AsyncMethodT handles the plumbing of the dispatch mechanism as well, ensuring (for example) that we can't do something like:

State::SetMethod(new Method(&NotMyClass::NotMyMethod));

without the compiler making a fuss. By convention, I use signature of unsigned(T::*Impl)(); for my async methods.

Now, we can hand off an instance to the input queue. We avoid the temptation to mess around with the instance by not keeping a reference to it and passing ownership to the input queue.:

IO::Queue *pInput = Thread::GetInput();
pInput->Post(new MyAsyncClass());

The arrival of this object causes the IOCP to wake up a worker thread, which has been parked since it called pInput->Fetch.

for(;;) {

IO::IAsyncState* pState = NULL;
	pInput->Fetch(&pState, INFINITE);


	unsigned ret = pState->Dispatch();
	if(ret == IO::Queue::ERROR_YIELD) 

With the retrieved pointer to an instance of IAsyncState in hand, the worker simply invokes IAsyncState::Dispatch(). AsyncStateT's implementation of Dispatch hands the call off to the currently assigned instance of IAsyncMethod. AsyncMethodT's implementation of IAsyncMethod::Dispatch is shown in Listing Four:

Listing Four: The dispatch method.
unsigned IO::IAsyncMethod::Dispatch(IO::IAsyncState* pState)
AsyncStateT<T>* pContext = dynamic_cast<AsyncStateT<T>*>(pState);

	T* pInst = pContext->Instance();
	unsigned ret = (pInst->*_impl)();

	return ret;

First, we unpack the instance we passed in, and the combination of dynamic_cast and assert ensure that we haven't somehow managed to incorrectly map an instance of the generic IAsyncState interface. Actually, the dynamic_cast could accomplish that on its own by returning a NULL pointer that would result in an OS fault when we tried to use it, but the assert

unsigned ret = (pInst->*_impl)();

_impl is a reference to the method which we set in our class constructor (which, you may recall, was Initialize).

unsigned Initialize()
	_counter = 10;

	State::SetMethod(new Method(&MyAsyncClass::Step));

	return IO::Queue::ERROR_YIELD;		

This routine is now executing in a worker thread and we have assigned it the herculean task of setting the _counter member to 10.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.



Pool* pPool = reinterpret_cast{Pool*}(param);
This should rather be a static_cast.


Have a look at AsyncSwarm::Initialise. It creates AsyncSwarmHelpers as a distribution mechanism. At present it uses DefaultHelperCount which is a const set to 4. Bump that up to at least the number of cores you are expecting and see how you go. I should have made it a runtime assessed value. I'll patch the code.


Yes. I would be interested to know if there are ways to reduce the overhead. I also ran the swarm demo at home on a Intel i7 920 quad-core w/hyper-threading (8 cores showing in task manager). The tick count was about equal for both cases but no better for async.


Hi Ekim, I'm away for a few days and don't have the code with me. I'll have a look when I'm home again. My immediate thoughts are that with 12 cores the distribution overhead is starting to become greater than the size of the problem i.e. the size of the swarm.


I'm getting a tick count of ~30 for DoSyncSwarm() and >90 for DoAsyncSwarm(). This is on release build in Visual Studio Express 2012 Desktop under Windows 7 x64 on a 12-core Xeon X5680. Executable run from a command prompt.