Mircea Ispas
Mircea Ispas

Reputation: 20790

Asynchronous Completion Handling

I have this situation:

void foo::bar()
{
    RequestsManager->SendRequest(someRequest, this, &foo::someCallback);
}

where RequestsManager works in asynchronous way:

Is it possible to have foo::someCallback called in the same thread as SendRequest? If not, how may I avoid following "callback limitation": callbacks should not make time consuming operations to avoid blocking the requests manager.

Upvotes: 0

Views: 197

Answers (3)

Roman Saveljev
Roman Saveljev

Reputation: 2594

I can see few ways how to achieve it:

A) Implement strategy similar to signal handling

When request processing is over RequestManager puts callback invocation on the waiting list. Next time SendRequest is called, right before returning execution it will check are there any pending callbacks for the thread and execute them. This is relatively simple approach with minimal requirements on the client. Choose it if latency is not of a concern. RequestManager can expose API to forcefully check for pending callbacks

B) Suspend callback-target thread and execute callback in the third thread

This will give you true asynchronous solution with all its caveats. It will look like target-thread execution got interrupted and execution jumped into interrupt handler. Before callback returns target thread needs to be resumed. You wont be able to access thread local storage or original thread's stack from inside the callback.

Upvotes: 1

Kiril Kirov
Kiril Kirov

Reputation: 38173

Depends on "time-consuming operations"'s definition.

The classic way to do this is:

  • when the request is processed, the RequestManager should execute that &foo::someCallback
  • to avoid blocking the request manager, you may just rise a flag inside this callback
  • check that flag periodically inside the thread, which called RequestsManager->SendRequest
  • This flag will be just a volatile bool inside class foo

If you want to make sure, that the calling thread (foo's) will understand immediately, that the request has been processed, you need additional synchronization.

Implement (or use already implemented) blocking pipe (or use signals/events) between these threads. The idea is:

  • foo's thread executes SendRequest
  • foo starts sleeping on some select (for example)
  • RequestManager executes the request and:
    • calls &foo::someCallback
    • "awakes" the foo's thread (by sending something in that file descriptor, which foo sleeps on (using select))
  • foo is awaken
  • checks the volatile bool flag for already processed request
  • does what it needs to do
  • annuls the flag

Upvotes: 1

Martin James
Martin James

Reputation: 24867

No - calls/callbacks cannot change thread context - you have to issue some signal to communicate between threads.

Typically, 'someCallback' would either signal an event upon which the thread that originated the 'SendRequest' call is waiting on, (synchronous call), or push the SendRequest, (and so, presumably, results from its processing), onto a queue upon which the thread that originated the 'SendRequest' call will eventually pop , (asynchronous). Just depends on how the originator wshes to be signaled..

Aynch example - the callback might PostMessage/Dispatcher.BeginInvoke the completed SendRequest to a GUI thread for display of the results.

Upvotes: 3

Related Questions