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);
}
}
}
Related
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
I use a BackgroundWorker and do this:
private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Text = "RunWorkerAsync()";
backgroundWorkerLoading.RunWorkerAsync();
}
private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e)
{
UnsafeThreadMethod("hello");
EvenUnsaferThreadMethod();
}
And now the two methods.
private void UnsafeThreadMethod(string text)
{
toolStripLabelRssFeedData.Text = text;
}
private void EvenUnsaferThreadMethod()
{
panelLoading.Visible = true;
}
I don't understand why UnsafeThreadMethod doesn't throw the following exception but EvenUnsaferThreadMethod does.
Cross-thread operation not valid: Control 'panelLoading' accessed from a thread other than the > thread it was created on.
According to the message it's because toolStripLabelRssFeedData was created on the same thread but it wasn't.
I thought that I can't call controls created by the main thread and have to use the ProgressChanged event. What's going on?
And I have a second question. What is the advantage of doing it like this when I can use ProgressChanged? What should I do?
private void EvenUnsaferThreadMethod()
{
if (panelLoading.InvokeRequired)
{
panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); }));
}
else
{
panelLoading.Visible = true;
}
}
To the first question:
the cross-thread exception is deliberately thrown in Debug mode. This means there is (conditional) code checking on InvokeRequired built into most of the GUI controls. Like the Panel.
Apparently the ToolstripLabel does not make this check. Since it does not derive from Control that could be because it is outside the scope of this safety net.
Since the standard disclaimer "Any instance members are not guaranteed to be thread safe" applies to the ToolstripLabel I would just go with the normal InvokeRequired logic when setting the Text.
For your first question, I am not entirely sure, but a review from online seems to show that sometimes this will not throw an exception, but it will not update the label. Is that the case here? Is your label being updated along with having no exception?
However, I can answer you second question right now. The ProgressChanged event is meant for exactly what it sounds like. It is supposed to be called to let the UI thread know the status of the backgroundworker so that it can update itself appropriately. The original calling thread (UI in this case) is the one that is used for the ProgressChanged, so when it updates it does not need to call Invoke. But, this should really only be done for showing the progress of a background worker.
Now, if it is not an update that you are trying to pass to the calling method, then I would suggest just passing your return data back through the RunWorkerCompleted event. This passes all of your final data back up to the original (UI) thread, so that it can update the UI without any need for an Invoke.
So, yes your call to Invoke will work, though. However, understanding what each of the other events are for can help you understand why to use one way over another. Maybe a ProgressChanged event fits better? It can also declutter your code from having unnecessary invokes.
Update to first q
I still cannot find anything about the toolstrip not needing the invoke. In fact I am finding the opposite using google searches like "toolstriplabel no cross thread exception" or "toolstriplabel invoke", etc. However, as henk mentioned, the toolstriplabel doesn't inherit from control so that might explain why no invoke is required. However, my suggestion is to assume that it will act like any other UI control and make sure it is updated on the UI thread to be safe. do not rely on quirks. Better safe than sorry, you never know if things like this might change, especially since it is logically a UI item to most..,
The advantage of your second choice is that it works :)
All UI elements are created on main UI thread and, what is more important from this question perspective, is that can be acessed only within that thread.
This is the reason why your first case fails and that is the reason your second case will work. Invoke()... will redirect required merhod call to the main UI thread.
Hope this helps.
When using the thread, 'invoke' is being used to avoid 'Cross Thread'(1)
but, sometimes 'timer object' is being used to avoid 'CrossThread' (2)
like this(for example)
public partial class Form1 : Form
{
private bool bCheckState = false;
public Form1()
{
InitializeComponent();
}
//Button Click
private void btnWork_Click(object sender, EventArgs e)
{
Thread m_Thread = new Thread(new ThreadStart(Work));
m_Thread.Start();
}
private void Work()
{
bCheckState = true;
// not use invoke
}
private void timer_Tick(object sender, EventArgs e)
{
if (bCheckState)
{
//tbxDisplay is winform's textBox control - printing data
tbxDisplay.Text = bCheckState.ToString();
bCheckState = false;
}
}
}
which one is more effective? 'between (1) and (2)'
Could it be a problem if we scatter the data processed within 'thread' after checking it in the 'timer event', without using 'invoke' or other methods? (We heard that to avoid 'Cross-Thread' when printing the data processed within 'thread', scattering the data in the 'timer event' with additional 'timer object' has been used quite often as it is neither beneficial nor harmful).
Just use a BackgroundWorker instance and handle the ReportProgress and/or RunWorkerCompleted events, which are already in the right thread.
As Ben Voigt suggested, a BackgroundWorker is probably what you should be using here, unless you have a good reason to want to use something else.
"Effective" is a rather vague means of comparison. Its not entirely clear what you're looking for in the two options you are considering.
BackgroundWorkers are simple and easy to understand, and they avoid the use of timers.
Invoke is more effective than a timer in the sense that there will be less of a delay between bCheckState becoming true and the text being updated. It will also be less CPU-intensive, since you won't have a timer polling at a set interval.
The Timer is more effective in the sense that the thread won't have to stop while invoking to update the text, but it is a bit inefficient because it is going to waste CPU time checking if the boolean has changed, and there could also be a delay of up to the timer interval length before the form changes.
As another alternative, BeginInvoke could be used to update the form without the use of a timer, and without the thread having to wait for the invoke to complete. However, if it raises an exception, your thread might not find out unless you also then call EndInvoke, which will also halt execution of the thread until the invoke is complete.
They all have their advantages and disadvantages, and you can't really call any particular one more "effective" in general.
I have an app that crawls a network looking for movies, their titles, length and last accessed time. Since there are a lot of computers on the network, this can take awhile and I would like to update my listview in real time. Heres what I have so far but its not working at all.
private void PopulateListView()
{
this.listView1.SuspendLayout();
listView1.Items.Clear();
// go thru list of movies to add
foreach (string movie in listviewMovieList)
{
ListViewItem item1 = new ListViewItem(movie);
listView1.Items.AddRange(new ListViewItem[] { item1 });
}
this.listView1.ResumeLayout();
}
This gets called by my background workers ProgressChanged method:
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string movie = (string)e.UserState;
if (movie != null)
{
listviewMovieList.Add(movie);
PopulateListView();
}
this.progressBar1.Increment(e.ProgressPercentage);
}
The problem is that it isn't slow enough. You are calling ReportProgress() too often. It depends on how much work the UI thread does, but do it roughly several hundred times per second and the UI thread freezes, not getting around do doing its normal duties anymore. Like painting the list view. Your code is very expensive, clearing and repopulating the ListView requires lots of Windows messages.
At least don't do it for one movie at a time, batch it up and use the AddRange() method. One call per 50 msec is ideal, a human cannot read any faster than that anyway. Slow down the worker thread by using Invoke() instead of BeginInvoke(). ListView.VirtualMode can help.
I think the issue might be to cross thread calls to WinForm UI controls.
Take a look at
Control.InvokeRequired Property
Gets a value indicating whether the
caller must call an invoke method when
making method calls to the control
because the caller is on a different
thread than the one the control was
created on.
and Control.BeginInvoke Method (Delegate)
Executes the specified delegate
asynchronously on the thread that the
control's underlying handle was
created on.
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();