Reputation: 26346
I'm working on a wrapping library for a robot controller, that mostly relies on P/Invoke calls.
However, a lot of the functionality for the robot, such as homing, or movement, takes quite a while, and do thread locks while running.
So I'm wondering how I can wrap the functionality in a async manner, so the calls don't block my UI thread. My idea so far is to use Tasks, but I'm not really sure it's the right approach.
public Task<bool> HomeAsync(Axis axis, CancellationToken token)
{
return Task.Factory.StartNew(() => Home(axis), token);
}
Most of the MSDN articles on the Async model in .NET as of right now, mostly is relaying on libraries already having Async functionality (such as File.BeginRead and so on). But I can't seem to find much information on how to actually write the async functionality in the first place.
Upvotes: 10
Views: 3021
Reputation: 26346
After some great discussion, I think something like this will be the golden middleway.
public void HomeAsync(Axis axis, Action<bool> callback)
{
Task.Factory
.StartNew(() => Home(axis))
.ContinueWith(task => callback(task.Result));
}
This is using the best of both worlds, I think.
Upvotes: 6
Reputation: 29640
My first reaction is that this is not something you should do in the library. The primary reason is that the way you implement such a system may depend on the type of interface you are building upon the library.
That said, you have basically two choices. First is the IAsyncResult
. A good description of this can be found at http://ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html.
The second option is to create commands with callback events. The user creates a command class and sets a callback on that. Then, you schedule the command to a ThreadPool
and after the command has been executed, you raise that event.
Older interfaces of the .NET framework primarily implemented the IAsyncResult
approach, where newer interfaces tend to implement the event callback approach.
Upvotes: 1
Reputation: 26904
Have you ever tried async delegates? I believe there is nothing simpler than it.
If your thread-blocking method is void Home(Axis)
you have first to define a delegate type, ie. delegate void HomeDelegate(Axis ax)
, then use the BeginInvoke
method of a new instance of HomeDelegate pointing to the address of Home method.
[DllImport[...]] //PInvoke
void Home(Axis x);
delegate void HomeDelegate(Axis x);
void main()
{
HomeDelegate d = new HomeDelegate(Home);
IAsyncResult ia = d.BeginInvoke(axis, null, null);
[...]
d.EndInvoke(ia);
}
Please bear in mind that using the EndInvoke somewhere (blocking the thread until the method is finally over, maybe in conjunction with polling of IAsyncResult.Completed property) is very useful to check if your async task has really been completed. You might not want your robot to open its arm and leave a glass until the glass is over the table, you know ;-)
Upvotes: 5