Channels ▼
RSS

C/C++

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>
{

	public:

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

private:

	    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:

MyAsyncClass()
:_counter(0)
{
State();
	State::SetInstance(this);
	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);

if(!pState) 
    break;

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

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);
	assert(pContext);

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

	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.
 

Comments:

ubm_techweb_disqus_sso_-b651efdb98a5d6bd2b3935d0c3f4a5e2
2013-03-31T00:40:37

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


Permalink
ubm_techweb_disqus_sso_-0aa7042a5aa42a59a4f1d61b0bd57f5b
2013-02-23T05:04:44

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.


Permalink
ubm_techweb_disqus_sso_-bdd00cbb54329c26515753651acc4286
2013-02-22T15:43:26

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.


Permalink
ubm_techweb_disqus_sso_-0aa7042a5aa42a59a4f1d61b0bd57f5b
2013-02-21T23:42:16

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.


Permalink
ubm_techweb_disqus_sso_-06fab0b35f8faf2d1b06cda412226c60
2013-02-20T15:16:13

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.


Permalink

Video