How to solve these problems with Asynchronous Callback? - c#

I need to run 5 algorithms parallely each takes an image as input and gives image as output. After each of these is done, I need to display the 5 output images. I'm using Asynchronous Callback using delegates for this task.
So, I created 5 delegates for these 5 algos and calling them like algo1Delegate.BeginInvoke().
Algorithms are running fine and giving the output too. I'm facing 2 problems in displaying these images.
For displaying images, I created a class ImageViewer (windows form with picturebox element in it).
//ImageViewer constructor
ImageViewer(Image img, String Title)
{
this.pictureBox1.Image = img;
this.Text = Title;
}
I'm displaying images like this:
void showImage(Image image, String title)
{
ImageViewer imageviewer = new ImageViewer(image, title);
imageviewer.Show();
}
Since I need to display an image after algo. I'm passing new AsyncCallback(showImage) delegate for each of these BeginInvoke() as 3rd parameter
private void showImage(IAsyncResult iasycResult)
{
MessageBox.Show("white" + Thread.CurrentThread.ManagedThreadId);
// Retrieve the `caller` delegate.
AsyncResult asycResult = (AsyncResult)iasycResult;
caller = (Algo1Delegate)asycResult.AsyncDelegate;//### PROBLEM!!!
// Retrieve the string Title that is passed in algodelegate.BeginInvoke().
string title = (string)iasycResult.AsyncState;
Image outputImage = caller.EndInvoke(iasycResult);
showImage(outputImage, title);
}
I think you can see the problem in the above callback function. it only works for Algo1 for other 4 alog's it needs to be casted to Algo2Delegate , Algo3Delegate etc.. because asycResult.AsyncDelegate is of type object. How can I solve this problem? How can I make it work for others too?
The imageViewer window is getting "unresponsive". I don't understand why? ImageViewer object is initialized and displayed on the same thread for each of these algos. Why is it becoming unresponsive.
Any other alternative solutions?
PS: I cannot declare one delegateType for all the algos since there are some differences in input parameters.
EDIT:
Well, I got enough inputs for my 1st and 3rd questions. I used separate callbacks for each of these algorithms. My 2nd problem is still unsolved. I changed the constructor of ImageViewer() Just to check if they are executing on two different threads:
public ImageViewer(Image img, String title)
{
InitializeComponent();
if (pictureBox1.InvokeRequired) MessageBox.Show("You must Invoke()");
else MessageBox.Show("No need of Invoke()");
this.pictureBox1.Image = img;
this.Text = title + " : Image Viewer";
}
in every case it says No need of Invoke(). I don't understand what is the problem. Can any one please address this too? I don't get any execptions also. Just the window is becoming unresponsive. I checked if algorithms are causing any trouble. But no, they arent.

I can't think of a clean solution to your problem. You'd have to write fugly code like this:
AsyncResult result = (AsyncResult)iresult;
if (result.AsyncDelegate is AsyncDelegate1) {
(result.AsyncDelegate as AsyncDelegate1).EndInvoke(iresult);
}
else if (result.AsyncDelegate is AsyncDelegate2) {
(result.AsyncDelegate as AsyncDelegate2).EndInvoke(iresult);
}
//etc...
ComputationResult answer = result.AsyncState as ComputationResult;
Yuck. You really ought to have an individual callback method for each delegate type. A generic method cannot help here, the constraint cannot be a delegate type. A lambda in the BeginInvoke method call doesn't look that much better:
var task1 = new AsyncDelegate1(Compute1);
var result1 = new ComputationResult("task1");
task1.BeginInvoke(42, result1,
new AsyncCallback((ia) => {
AsyncResult result = ia as AsyncResult;
(result.AsyncDelegate as AsyncDelegate1).EndInvoke(ia);
CommonCallback(result.AsyncState as ComputationResult);
}),
result1);
Nah. I'd tackle this by using only one delegate type. The WaitCallback type is suitable, although mis-named, you should write little helper classes that store the arguments for the delegate target so you can pass it through the WaitCallback.state argument.
Your second problem is induced because you are creating the ImageViewer instance in the callback method. The callback executes on a threadpool thread, not the UI thread. InvokeRequired returns false because the PictureBox control was created on the threadpool thread. This threadpool thread is however not suitable to display UI components, it doesn't pump a message loop. And has the wrong apartment state. And it terminates too soon.
InvokeRequired will return the proper value (true) when you use a Control that was created on the UI thread. Your main startup form for example. Or Application.OpenForms[0]. There's little point in using InvokeRequired however, you know for a fact that the callback executes on the wrong thread. Just use BeginInvoke directly. The invoked method should create the ImageViewer instance.
You are well on your way re-inventing the BackgroundWorker class. It does exactly what you are trying to do. But takes care of the gritty details of getting the RunWorkerCompleted event fired on the correct thread. You ought to consider it.

You should substitute the delegates with a consistent hierarchy with the common methods you need.
AsyncCallbackClass caller = (AlgoDelegate)asycResult.AsyncState;
Image img = caller.DoCallBack(iAsyncResult);
then you have a hierarchy with:
class AsyncCallback1 : AsyncCallbackClass
{
Image DoCallBack(IAsyncResult result)
{
// Call specific callback with specific parameters
}
}
class AsyncCallback2 : AsyncCallbackClass
{
Image DoCallBack(IAsyncResult result)
{
// Call specific callback with specific parameters
}
}
Basically you'll be constructing your callbacks as a hierarchy of classes so that the "signature" of the main method is the same (a method that takes an IAsyncResult) and returns an image, but the way each "delegate" (which is now a full class) implements the call is unique for each implementation.
Take a look at Replace Delegate with inheritance.
Edit: From the msdn page.
true if the control's Handle was
created on a different thread than the
calling thread (indicating that you
must make calls to the control through
an invoke method); otherwise, false.
I assume you're creating the ImageBox in the ImageViewer, and the ImageViewer is being created in the callback so, by definition, the ImageBox has been created by the same thread and therefore does not need to be invoked.

Can you wrap your calls into lambda expression and then, have a method that starts the delegate:
private void run(Action<Image,Image> delegate, Image inputImage)
{
delegate.BeginInvoke(inputImage, // all the callback stuff here );
}
But then call your run method with lambdas:
run(image => algo1(image, otherVar, otherVar2));
run(image => algo2(image, otherVar, otherVar2, otherVar3, otherVar4));
and so on

I was doing something similar some months ago, I was using ThreadPool:
http://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspx
http://www.switchonthecode.com/tutorials/csharp-tutorial-using-the-threadpool
It is managing the threads for you and is fairly easy to use for tasks which are not requiring complex multithreading.

#1. You have five delegates but you have defined a common callback method for each. So you will have a problem finding out what delegate actually has completed. One way is to have different callback method for every delegate.
#2 You should not update the UI from a different thread than on what it was created. If it is true, we use Control.Invoke to make sure the call is marshaled to the UI thread.
MethodInvoker updateImageViewer = delegate
{
ImageViewer imageviewer = new ImageViewer(image, title);
imageviewer.Show();
};
if (this.pictureBox1.InvokeRequired)
this.pictureBox1.Invoke(updateImageViewer);
else
updateImageViewer();

Related

Invoke not switching back to separate thread

I have the method below that is running on a separate thread from the main UI thread, and I am trying to update the ListBox control on the main thread. The code does work and the field does get updated, but when the Invoke method runs it switches to the main thread. The problem is that the code after the Invoke also runs on the main thread, but I need it to run on the separate thread.
public static void Status_Message(string str, int destination, int prompt)
{
//Clear_System_Message_Area();
sysmsg++;
ListBox tl = Application.OpenForms["GMLEC"].Controls["groupBox2"].Controls["TestList"] as ListBox;
if (!tl.InvokeRequired)
{
tl.Items.Add(str);
tl.Refresh();
}
else
{
tl.Invoke(new Action<string, int, int>(Status_Message), str, destination, prompt);
}
if (destination == 1)
{
Printer.Output(str);
}
if (prompt == 1)
{
Pause(false);
}
if (sysmsg > 23)
{
Pause(true);
}
}
Is there a way to make it go back to the separate thread?
If you don't want code run on the UI thread, don't invoke the method that contains it.
For what it's worth, I disagree with any code that uses InvokeRequired. First of all, you ought to know from the context whether invoke is required or not. If you don't know which thread the code that's executing is on, then there is too much coupling between the UI and background task parts of the code.
But secondly, the Control.Invoke() method has to check which thread is current anyway, because it has to work whether you are on the UI thread or not. You can always call it safely from the UI thread, and when you do, it can't go queueing up your delegate for invocation and then waiting for it, because that would deadlock. It has to just invoke the delegate directly, but only in that case, which means it's doing the InvokeRequired check anyway.
So, taking all of that into account, just write your code to always invoke the part that needs invoking, and be done with it.
For example:
public static void Status_Message(string str, int destination, int prompt)
{
//Clear_System_Message_Area();
sysmsg++;
ListBox tl = Application.OpenForms["GMLEC"].Controls["groupBox2"].Controls["TestList"] as ListBox;
tl.Invoke((MethodInvoker)(() =>
{
tl.Items.Add(str);
tl.Refresh();
}));
if (destination == 1)
{
Printer.Output(str);
}
if (prompt == 1)
{
Pause(false);
}
if (sysmsg > 23)
{
Pause(true);
}
}
Now, some other notes about this:
It's doubtful that you should be calling Refresh(). Let Winforms deal with updating on its own. If you've somehow interfered with it refreshing the window normally, fix that. Don't hack around it by calling Refresh() yourself.
It's almost certain that there's a better way to encapsulate the ListBox object than by always looking it up from the top of the UI control graph. For example, maybe the actual object should have been referenced directly (e.g. from a TestList field) and passed to the code that will eventually need it.
Finally, and most important, the fact that you're using Invoke() at all is a big warning flag in modern code. There's a decent chance that your overall code could be refactored to use async/await in a way that allows it to read more naturally and still work correctly, but at the very least it would be better to use Progress<T> to mediate cross-thread updates like this.
To address any of these issues would be beyond the scope of the current question, but I do encourage you to take the suggestions under consideration.
This might help...
normally I use Invoke() to activate a part of the script after a certain time. Invoke() Does NOT repeat, if you want it to repeat you can use InvokeRepeating().
another option is to use "Multi-Threading". Here's how to use Multi-Threading:
using System.Threading
public static Thread newThread = new Thread(MultiThread)
private void Start()
{
newThread.Start()
//also newThread.Abort() to quit the thread
}
private static void MultiThread()
{
// this is the seporate thread
// i normally use this for a "while (True)" loop cause it will stop responding
//otherwise
}
srry for any typos
Hopefully this helps

How do i pass data from Thread to UI-Thread and view that data?

I really don't know how to properly get data from a Thread.
In a thread (or Task, doesnt matter) i want to calculate a lot of doubles. When this is finished i want to show this data in a grid and in a graphic-chart. So i tried to return some type of
Observable<List<double>>
When i then wanted to create a "new ViewModel(data)", i get exceptions cause of threads.
So how do i properly get such a list back from a thread and use it in UI?
Or maybe pass this data while calculating to show some live values would also be nice..
thanks for answers, just need a few tips
This kind of functionality is common and is often accomplished using the BackgroundWorker Class. There is a code example on the linked page and you can find another with feedback in my answer to the How to correctly implement a BackgroundWorker with ProgressBar updates? question on this website.
Alternatively, you can use the Dispatcher object from the UI thread to pass values to that thread. Note that each thread has it's own Dispatcher, so be sure to call the one from the UI thread. You can use this little helper method:
public object RunOnUiThread(Delegate method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
You can use it like this:
RunOnUiThread((Action)delegate
{
// You can run any number of lines of code on the UI Thread here
});
Or inline, like this:
RunOnUiThread((Action)delegate { UpdateData(); });
I have this method in a separate class that has constructors like this:
private UiThreadManager(Dispatcher dispatcher)
{
Dispatcher = dispatcher;
}
public UiThreadManager() : this(Dispatcher.CurrentDispatcher) { }
I call this constructor on the UI thread to ensure that the Dispatcher that I will be using is in fact the Dispatcher from the UI thread.

How to let the code wait to be executed until the other event handler finished?

In the following code, I want to use the geometryService (a utility class provided by third party) to sequentially calculate several shape area. I failed because the second time area calculation mustn't wait until the first calculation is finished. To resolve this issue, I can put the second area calculation into the finish calculation event handler, but the code is a mess. Is there a better way I can make geometryService.AreasAndLengthsAsync(secondShape) wait to execute untilgeometryService.AreasAndLengthsAsync(firstShape) is finished executing?
Shape firstShape = new Shape();
Shape secondShape = new Shape();
GeometryService geometryService = new GeometryService();
geometryService.AreaAndLengthsCompleted += GeometryService_AreasAndLengthsCompleted;
geometryService.AreasAndLengthsAsync(firstShape);
geometryService.AreasAndLengthsAsync(secondShape);
private void GeometryService_AreasAndLengthsCompleted(object sender, AreasAndLengthsEventArgs args){ }
You could place each Shape in a Queue<Shape>
Then kick off the first calculation, and in the completed handler check the queue for any other Shapes and if there is one, process it.
Additionally, the method you are calling is AreasAndLengthsAsync(). By convertion most API designers will include synchronous alternatives named the same byt without the Async part.. so look for AreasAndLengths() as an alternative.
This is a classic problem with async methods. If you're using the new MS Async CTP, you can encapsulate some of this stuff fairly cleanly, but if you're stuck using the traditional stuff, it's difficult to get clean code out of this.
One of the approaches that I take is to wrap the event-handler pattern with a continuation-passing pattern. It's not perfectly clean, but I like the look of the resulting code better. So you could do something like this:
public static void GetAreasAndLengthsAsync(Shape shape, Action<SomeResult> callback)
{
var geometryService = new GeometryService();
geometryService.AreasAndLengthsCompleted += (s, e) =>
{
if (callback != null)
{
callback(e.SomeResult);
}
};
geometryService.AreasAndLengthsAsync(shape);
}
And you can then use it like this:
GetAreasAndLengthsAsync(firstShape, firstShapeResult =>
{
GetAreasAndLengthsAsync(secondShape, secondShapeResult =>
{
DoSomethingWithTheseResults(firstShapeResult, secondShapeResult);
});
});
Something like that, at any rate. The formatting is kinda ugly, but at least it expressed your intent fairly well. (Haven't compiled the code, there may be errors.)
If you don't like recreating the geometryService each time, you can do that at the field level in your class, and then pass the callback method as part the UserState parameter that most Async methods include.
You can use AutoResetEvent or ManualResetEvent, simply define one at the top of your class, and call Wait in the event that you want to wait for the other event, and then call Set in the event that you your waiting for, Wait will block until Set is called.
http://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
I would like to add that this is not ideal, but it you must have Serialized events and you are relying on a third party API than this may be the only option.

InvokeRequired is true on PictureBox. How to deal with this?

I had another question on my PictureBox calls giving me 3 kinds of errors, some great answers came in particularly from Conrad Frix. So it led me to figure out where my problem is, but now to fix it I am not 100% sure on.
Basically I have a Windows Form timer that is checking for some event to be true, if it is, then it tells the system to send some data out 2 seconds after said event (a value ) is past some threshold.
I think all the timers I have is creating a nasty race condition with my PictureBox that I use in several places to get the image from:
new Bitmap(myPicBox.Image);
etc...
I read somewhere that the interval on the timer should be at least 50. Set that from 33. I found out I can do a picCapture.InvokeRequired to see if its going to basically die. I know I need to use a delegate but only ever used those to set something... not to get an image from.... not sure how to set that up... I know what is indeed causing it, it is this combination of code:
private void timer1_Tick(object sender, EventArgs e)
{
if(someCOnditionTrue)
{
TimerCallback tc = new TimerCallback(sendDataFast); //only
//doing all this so i can have the method run two seconds after
// the condition is detected to be true.
System.Threading.Timer t = new System.Threading.Timer(tc, null, 2000, Timeout.Infinite);
}
}
void sendDataFast(Object stateObject)
{
//using this so the execution is not haulted while the sending of data takes place.
EmergencyDelegate delEmergency =
new EmergencyDelegate(mic.sendEmergencyData);
Image imgclone;
if (picCapture.InvokeRequired)
{
Console.WriteLine("HFS Batman! its going to die ");
}
lock (lockObject2) //i admit no clue what im doing here and doesn't seem to help.
{
Image img = picCapture.Image;
imgclone = (Image)img.Clone();
}
delEmergency.BeginInvoke(imgclone, null, null); //deep in the call to
//sendEmergencyData i get the **ParameterNotValid** almost everytime.
imgclone.Dispose(); //to free memory?
}
As per my previous question, no longer seem to get the memory issues or other errors in the timer1_tick event... (out of memory error was one).
I think the biggest issue is how can I handle the picCapture.InvokeRequired when I need its image data? I am certain its the threading timer call inside the timer1_click I do that is causing this....
As its name suggests, InvokeRequired means you need to call Invoke (or BeginInvoke) when accessing the control.
Note that this is Control.Invoke/Control.BeginInvoke, not the Invoke/BeginInvoke which are present in delegates... although you'll need a delegate in order to call Invoke/BeginInvoke, just to add more confusion to the mix.
See the Windows Forms section of my threading tutorial for more details. The overall tutorial could do with updating, but I believe this bit is okay. In other situations you may also want to consider using BackgroundWorker, but I don't think that's likely to be relevant for you in this particular case.
I think that you have got a wrong understanding about InvokeRequired. InvokeRequired indicates that the current thread is not the same as the UI thread and it will not be safe to access the control state now. If such is the case then you have to use Control.Invoke to marshal call to the UI thread and then access the control state. Read here on MSDN for more info.
In your case, unless the PictureBox image is changing, I would suggest that you rather make a clone of the image upfront and use that. Otherwise you need to use Control.Invoke.
You've got too many threads going to bring this to a good end. Both the Timer and the delegate's BeginInvoke() method will use a threadpool thread. The problem is that the PictureBox.Image property is only partially thread-safe. It can be accessed by only one thread at a time. Your code will die with an exception when the image is painted by the UI thread at the exact same time your code is calling the Clone() method.
Your lock statement doesn't solve the problem, the PictureBox is accessing the Image property without using that same lock. I would strongly recommend getting rid of the threading first, use a System.Windows.Forms.Timer instead of a System.Threading.Timer. It's Tick event is raised on the UI thread. That will however make the UI thread unresponsive while the event is running, it depends how long it takes whether that's noticeable to the user. More than, say, 100 milliseconds gets to be a problem.
The only other approach is to try to make the PictureBox control thread-safe. That's possible to some degree. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing the existing PB. Beware that this is only a partial solution, displaying an animated GIF or using the ImageLocation property will still bomb. Use the provided Clone method instead of calling Clone on the Image property.
using System;
using System.Drawing;
using System.Windows.Forms;
class MyPictureBox : PictureBox {
private object locker = new object();
public new Image Image {
get { return base.Image; }
set { lock (locker) { base.Image = value; } }
}
public Image Clone() {
lock (locker) {
return (this.Image != null) ? (Image)this.Image.Clone() : null;
}
}
protected override void OnPaint(PaintEventArgs pe) {
lock (locker) {
base.OnPaint(pe);
}
}
}

C# Func Delegate throws Thread Exception

So, maybe I misunderstood the usage of Func but
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
Creates a Thread Error when calling getCurrentValue(cb_message_type) from my Workerthread.
Whats the best solution to get the Selected Value of the Combobox?
Many thanks,
rAyt
Edit
MSDN
"The underlying type of a lambda expression is one of the generic Func delegates. This makes it possible to pass a lambda expression as a parameter without explicitly assigning it to a delegate."
Since windows controls have thread affinity, you have 2 options:
query this data before doing your threading code, for example passing it in as the state to the worker
query it in the worker via Control.Invoke
Since the first is trivial, I'll give an example of the second using captured variables:
object value = null;
yourCombo.Invoke((MethodInvoker) delegate {value=yourCombo.SelectedValue;});
string s = value.ToString();
Here the bits inside delegate {...} happen on the UI thread, even if the code around it is on the worker thread. You can mix the above either inside your func, or call the entire func once you've switched threads.
You need to call Control.Invoke with that delegate - or make the delegate itself call it.
Using a lambda expression doesn't change the threading requirements of Windows Forms - it just makes it easier to create a delegate.
You might want to make a convenience method to do this:
// (Untested)
public static Func<TControl, TResult> WrapInvocation(Func<TControl,TResult> func)
where TControl : Control
{
return control => {
return (TResult) control.Invoke(func);
};
}
Use as:
Func<ComboBox, string> getCurrentValue = s => s.SelectedValue.ToString();
getCurrentValue = WrapInvocation(getCurrentValue);
Then you can call getCurrentValue(comboBox) from any thread.
The problem is that UI controls can only be used on the UI thread,
You need to call the Invoke method within the other thread, like this:
Func<ComboBox, string> getCurrentValue =
s => s.Invoke(new Func<object>(() => s.SelectedValue)).ToString();
The Invoke method takes a delegate and executes it on the UI thread.
Generally speaking, you cannot access UI controls from a thread other than that they were created on. To overcome that, you'll either have to check ISynchronizeInvoke.InvokeRequired on the control in question and branch, invoke a delegate, etc. or use a SynchronizationContext. First option is very cumbersome, whereas second one is pretty elegant:
var synchronizationContext = WindowsFormsSynchronizationContext.Current;
string currentValue = "";
synchronizationContext.Send(
() => currentValue = getCurrentValue(comboBox),
null);
If the thread will simply be reading the ComboBox, the best option if practical is probably to have an event handler on the thread which grabs the ComboBox value any time it changes, and then exposes that value via property which can be read from any thread.

Categories

Resources