How do I call a DLL which does a time consuming task? - c#

In my WPF application, I have to communicate to a datastor over the serial port. I want to separate this communication into a class library for simplicity.
In my DLL, I will be issuing a command to the datastor and wait for 10 seconds to receive the response back. Once I get the response from the datastor, I compile the data to meaningful info and pass to the main application.
My question is how to make the main application to pause for a while to get the data from the external dll and then continue the processing with the data from the dll?
I use .net 4.0

Consider calling the DLL method in a new thread
Thread dllExecthread = new Thread(dllMethodToExecute);
and providing a callback from the main program to the dll which can be executed when complete (This prevents locking on the GUI).
edit: Or for simplicities sake if you just want the main program to wait for the DLL to finish execution subsequently call:
dllExecthread.Join();

Maybe you could go with TPL:
//this will call your method in background
var task = Task.Factory.StartNew(() => yourDll.YourMethodThatDoesCommunication());
//setup delegate to invoke when the background task completes
task.ContinueWith(t =>
{
//this will execute when the background task has completed
if (t.IsFaulted)
{
//somehow handle exception in t.Exception
return;
}
var result = t.Result;
//process result
});

Don't ever pause your main thread because it blocks the GUI. Instead you need to act on an event that the background communication fires. You could use the BackgroundWorker class - simply provide the result in RunWorkerCompleted.

Related

Questions about what runs on the main thread during c#'s async await

I'm having trouble understanding what runs on the main thread during an async await operation and would be grateful for some answers.
Let's say I have a button that is supposed to log the user in.
it is supposed to block all other user input while the login process transpires, show a progress view and then when the result comes in display it
and here is the method that performs the log in
button_clicked(object sender, EventArgs e) {
do_login(); //I do not await the result
do_some_other_stuff(); //this doesn't actually exist I just put it here to ask my questions
}
async Task do_login() {
string user_name = txtUser.Text;
string password = txtPassword.Text;
show_progress(true); //this is not an async method;
string error = await _login.do_login(user_name, password);//this is an async method that can take up to 20 seconds to complete;
show_progress(false);
if (error != null) {
show_error(error);
} else {
show_next_screen();
}
}
I have two questions on the above example
a) What will be run on the main thread?
If I understand it correctly only _login.do_login will be run on a seperate thread, all others will be on the main thread, is this correct?
b) In what order will the methods be executed?
Again if I understand it correctly, it will be :
do_login()
show_progress(true);
_login.do_login starts;
do_some_other_stuff();
_login.do_login finishes;
show_progress(false);
and it will continue from there
is this correct? if not, how can I achieve such a behaviour?
c) If my code above is correct then why do I keep receiving a warning that do_login() is not awaited? I do not wish to await it I just want it to run what it can and return when it wants, should I ignore that warning?
Technically, depending on the implementation of do_login, everything could run in the main thread. In this case I assume you're contacting a web server, so that part won't, but this is not always true. And asynchronous operation does not necessarily executes in another thread. One operation is asynchronous when:
It doesn't block the calling thread.
Usually, UI threads run an 'event loop'. So an asynchronous task could simply put a new piece of work into the event queue to be executed whenever the scheduler determines, but in the same thread. In this case you don't use two threads, but still, you don't have to wait for the task to complete and you don't know when it'll finish.
To be precise, all the code in your post will run in the main thread. Only the part in do_login that manages the connection with the server, waiting and retrieving data will execute asynchronously.
You're mostly right about the sequence, with a few adjustments:
do_login() (until the await)
login._do_login() starts executing
do_some_other_stuff()
...
login.do_login finishes
show_progress()
The answer to your main question is: it depends. The _login.do_login method will likely be put onto its own thread, but it actually depends on the .NET task scheduler. In WPF and ASP.NET it will be scheduled onto the thread pool if it doesn't immediately return a completed task.
The important part is that you know it will not block execution of the calling (in your case, the main) thread. Your understanding of the method flow is correct since you don't await do_login.
As far as the warning goes; you can mark do_login as async void to avoid it, though generally you only do that for event handlers which can then await a Task returning method. If you do go the async void route; make sure to put a try/catch in as such methods will throw all the way up to the root handler and can cause your app to crash.

Console Application with Message Pump

I'm trying to write a console application (C# .NET) that makes use of un-managed code in a 3rd party DLL.
The external assembly makes extensive use of callbacks. The sample application I have uses Windows Forms.
The sample code (Windows Forms) makes use of ThreadPool.QueueUserWorkItem
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
It would seem that with windows forms there is a message pump that handles the callbacks. This is not the case with a console app so I need to construct my own.
I've tried adding a reset event
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
static void main()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
resetEvent.WaitOne();
}
private void ConnectToControlPanel()
{
//Call external function from unmanaged DLL
resetEvent.Set();
}
That doesn't work.
My problem seems to be very much like this one but there is no real solution other than using Win.Forms and calling Application.DoEvents()
Edit
I modified my code thus:
Task task = Task.Factory.StartNew(() => ConnectToControlPanel());
while (task.Status != TaskStatus.RanToCompletion)
{
Application.DoEvents();
Thread.Sleep(500);
}
This works, the callbacks get called on progress and the result is successful rather than a timeout.
It doesn't feel right though to have to run that ugly loop every time I make an external call.
I've also tried spinning up another thread that constantly calls Application.DoEvents() but that didn't work, so I'm assuming it's got something to do with running in the same thread that made the call.

How can I have two separate task schedulers?

I am writing a game, and using OpenGL I require that some work be offloaded to the rendering thread where an OpenGL context is active, but everything else is handled by the normal thread pool.
Is there a way I can force a Task to be executed in a special thread-pool, and any new tasks created from an async also be dispatched to that thread pool?
I want a few specialized threads for rendering, and I would like to be able to use async and await for example for creating and filling a vertex buffer.
If I just use a custom task scheduler and a new Factory(new MyScheduler()) it seems that any subsequent Task objects will be dispatched to the thread pool anyway where Task.Factory.Scheduler suddenly is null.
The following code should show what I want to be able to do:
public async Task Initialize()
{
// The two following tasks should run on the rendering thread pool
// They cannot run synchronously because that will cause them to fail.
this.VertexBuffer = await CreateVertexBuffer();
this.IndexBuffer = await CreateIndexBuffer();
// This should be dispatched, or run synchrounousyly, on the normal thread pool
Vertex[] vertices = CreateVertices();
// Issue task for filling vertex buffer on rendering thread pool
var fillVertexBufferTask = FillVertexBufffer(vertices, this.VertexBuffer);
// This should be dispatched, or run synchrounousyly, on the normal thread pool
short[] indices = CreateIndices();
// Wait for tasks on the rendering thread pool to complete.
await FillIndexBuffer(indices, this.IndexBuffer);
await fillVertexBufferTask; // Wait for the rendering task to complete.
}
Is there any way to achieve this, or is it outside the scope of async/await?
This is possible and basically the same thing what Microsoft did for the Windows Forms and WPF Synchronization Context.
First Part - You are in the OpenGL thread, and want to put some work into the thread pool, and after this work is done you want back into the OpenGL thread.
I think the best way for you to go about this is to implement your own SynchronizationContext. This thing basically controls how the TaskScheduler works and how it schedules the task. The default implementation simply sends the tasks to the thread pool. What you need to do is to send the task to a dedicated thread (that holds the OpenGL context) and execute them one by one there.
The key of the implementation is to overwrite the Post and the Send methods. Both methods are expected to execute the callback, where Send has to wait for the call to finish and Post does not. The example implementation using the thread pool is that Sendsimply directly calls the callback and Post delegates the callback to the thread pool.
For the execution queue for your OpenGL thread I am think a Thread that queries a BlockingCollection should do nicely. Just send the callbacks to this queue. You may also need some callback in case your post method is called from the wrong thread and you need to wait for the task to finish.
But all in all this way should work. async/await ensures that the SynchronizationContext is restored after a async call that is executed in the thread pool for example. So you should be able to return to the OpenGL thread after you did put some work off into another thread.
Second Part - You are in another thread and want to send some work into the OpenGL thread and await the completion of that work.
This is possible too. My idea in this case is that you don't use Tasks but other awaitable objects. In general every object can be awaitable. It just has to implement a public method getAwaiter() that returns a object implementing the INotifyCompletion interface. What await does is that it puts the remaining method into a new Action and sends this action to the OnCompleted method of that interface. The awaiter is expected to call the scheduled actions once the operation it is awaiting is done. Also this awaiter has to ensure that the SynchronizationContext is captured and the continuations are executed on the captured SynchronizationContext. That sounds complicated, but once you get the hang of it, it goes fairly easy. What helped me a lot is the reference source of the YieldAwaiter (this is basically what happens if you use await Task.Yield()). This is not what you need, but I think it is a place to start.
The method that returns the awaiter has to take care of sending the actual work to the thread that has to execute it (you maybe already have the execution queue from the first part) and the awaiter has to trigger once that work is done.
Conclusion
Make no mistake. That is a lot of work. But if you do all that you will have less problem down the line because you can seamless use the async/await pattern as if you would be working inside windows forms or WPF and that is a hue plus.
First, realize that await introduces the special behavior after the method is called; that is to say, this code:
this.VertexBuffer = await CreateVertexBuffer();
is pretty much the same as this code:
var createVertexBufferTask = CreateVertexBuffer();
this.VertexBuffer = await createVertexBufferTask;
So, you'll have to explicitly schedule code to execute a method within a different context.
You mention using a MyScheduler but I don't see your code using it. Something like this should work:
this.factory = new TaskFactory(CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskContinuationOptions.None, new MyScheduler());
public async Task Initialize()
{
// Since you mention OpenGL, I'm assuming this method is called on the UI thread.
// Run these methods on the rendering thread pool.
this.VertexBuffer = await this.factory.StartNew(() => CreateVertexBuffer()).Unwrap();
this.IndexBuffer = await this.factory.StartNew(() => CreateIndexBuffer()).Unwrap();
// Run these methods on the normal thread pool.
Vertex[] vertices = await Task.Run(() => CreateVertices());
var fillVertexBufferTask = Task.Run(() => FillVertexBufffer(vertices, this.VertexBuffer));
short[] indices = await Task.Run(() => CreateIndices());
await Task.Run(() => FillIndexBuffer(indices, this.IndexBuffer));
// Wait for the rendering task to complete.
await fillVertexBufferTask;
}
I would look into combining those multiple Task.Run calls, or (if Initialize is called on a normal thread pool thread) removing them completely.

How would I use Background Worker to get my GUI to respond?

I made a short program which has just a button. When the button is pressed, functionA is executed, which also uses functionB and functionC. Inside functionA is a loop which executes functionB and functionC X amount of times. At the end of each loop, the progressbar gets incremented by 1. At the beginning of functionA, before the loop, there's a webservice which pulls data from a website, and passes that onto B and C for processing (data file manipulation and saving to disk).
My problem is that everything works fine, but while functionA is still running, the GUI is stuck, so I can't close/minimize/drag the window around, I have to wait until A is done. I researched and they say I should use BackgroundWorker, but as being a new programmer, I've no idea on how to use it. Can someone give me a simple way to use it?
The progressbar loads fine, but it's just that while the function is running, the whole window is frozen, and I want it so I can move the window around, etc while the program is running, instead of waiting until the function is complete.
Thank you!
Call your function asynchronously like the following and it will not freeze the UI.
private async void BeginProcessingAsync(Data d)
{
//Execute the long running task asynchronously
await Task.Run(() => functionA(d));
//Anything after the await line will be executed only after the task is finished.
anotherFunction(d); // if you have one..
}
To run your task, simply call BeginProcessingAsync(d);. Also, please note: If you're using newer versions of .NET, you might have to use await Task.Factory.StartNew(() => functionA(d)); instead of the above
Overall, you'll want to make sure your GUI doesn't get updated from another thread. Instead, the messages should go to a threadsafe location. For instance, you could have the thread building into something like a database and have the GUI using a timer to look for updated data flags.
There is a question with a lot more detail using delegates here.
Marc's answer was the simplest and best, in my opinion:
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From Dotnet Perls:
A Background Worker makes threads easy to implement in Windows
Forms. Intensive tasks need to be done on another thread so the UI
does not freeze. It is necessary to post messages and update the user
interface when the task is done.
Also, from MSDN, look at Task-based Asynchronous Pattern (TAP) if you're using C# 5.
The Task-based Asynchronous Pattern (TAP) is based on the
System.Threading.Tasks.Task and System.Threading.Tasks.Task
types in the System.Threading.Tasks namespace, which are used to
represent arbitrary asynchronous operations. TAP is the recommended
asynchronous design pattern for new development.

Call delegate method with controls asynchronously in a C# WPF application

I am developping a WPF application.
I have a couple of timers that work asynchronously and they are created with System.Threading.Timer objects.
new System.Threading.Timer(
new System.Threading.TimerCallback(Timer_Function),
null,
timing,
timing
);
Timer_Function()
{
/*code that runs asynchronously */
}
In order to update the controls that are in WPF view I use delegate methods called by Dispatcher.Invoke otherwise the compiler would raise InvalidOperationException (The calling thread cannot access this object because a different thread owns it.)
My problem is that the delegate method do not run asynchronously and i have to do a lot of work in it so the application stops.
What can i do to run delegate method asynchronously?
What you need to do is separate out your business logic for determining what you should display, from the code that displays the results of those calculations to the UI. The business logic, the non-UI code, should be run in a non-UI thread and compute some result. That result should then be given to a method that will marshal to the UI thread and then display those results.
If you need your program to continue executing when the Timer_Function() code is run you could use a Task.Run to perform the work on a worker thread.
As always with parallel execution you need to beware of synchronization issues. Make sure you don't need the results before the work is processed and dispathed. Using the dispatcher as you mentioned might be enough, just make sure you think it through.
Something like:
Timer_Function()
{
Task.Run(() =>
{
/* do your work here */
});
}
Sorry if I misunderstood your issue
For asynchronous tasks, use this -
Task.Factory.StartNew(() =>
{
// Code which needs to run asynchronously
}.ContinueWith(task =>
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
// Code in which you are updating UI
});
}

Categories