I'm doing a windows form and would like an audit task to happen every 30 seconds. This audit is essentially checking a series of services on remote computers and reporting back into a richtextbox the status.
Current I have this running in an endless background thread and using an invoker to update the richtextbox in the main form.
Is this best practice? If I made an endless loop in my main form that would prevent any of my buttons from working, correct?
I'm just curious if every time I want to create a periodic audit check I have to create a new thread which checks the status or file or what have you?
Edit: I looked further into the Timer class and decided to go with System Timer as it proved to be better with a longer function. Thanks for pointing me in the right direction.
You should look into the Windows Forms Timer class. You don't want a loop in your main form. It's better to use the timer to fire events which can be processed asynchronously on another thread.
(I assume this is a winform application)
Invoking on the main thread is the way to go. But what about using a timer instead of an endless loop? It gives you more control. And a the timer function would execute on it's own thread.
It's good practice to let long going work execute on a background thread, so that the main thread can work with the UI.
Related
I am writing a program that manages a bunch of timers.
The user has to start them manually, and is able to get information from each timer, to know the remaining time for example.
I don't want the GUI to freeze, therefore I don't want to have a timer on the main form thread that freezes the whole thing.
So, does the Timer class send the timer on a new thread, or it keeps it on the main UI thread?
Otherwise, should I use a Background Worker to accomplish this?
The System.Windows.Forms.Timer event runs on the UI thread.
Instead you can use a System.Threading.Timer which runs on a worker thread.
Ref. : Comparing the Timer Classes in the .NET Framework Class Library
Depends on the type timer you use, I suggest to read these articles to decide the best for you.
Could you please tell me how do I go about pausing my program for 500 milliseconds and then continue?
I read Thread.Sleep(500) is not good as it holds up the GUI thread.
Using a timer it fires a callback ...
I just want to wait 500ms and then continue to the next statement.
Please advise.
EDIT: I need to display a status bar message for 500ms and then update the message with a different one. Sorry, I meant 500 not 50.
EDIT: I do understand what all you have said. but: [I just want to wait 500ms and then continue to the next statement.] I think because it is such a short interval i am going do a Thread.Sleep(500) on the main GUI thread. Otherwise i would have to rewrite a lot of code to accomodate this brief interval of 500 milliseconds.
EDIT: i will try to reformat my status message so the pause is not needed.
Hmya, what you're trying to do is pretty fundamentally incompatible with the Windows programming model. A native Windows program is event driven. Your program is always idle, sitting inside a loop started by Application.Run(), waiting for Windows to tell it that something interesting happened that it should respond to. Paint requests, mouse clicks, timer expirations, stuff like that.
Your program should respond to this and filter what is interesting to you. When you drop a button on a form, you are always interested in the Click event, generated when Windows sends the MouseDown notification message. Your Click event handler runs some kind of custom code that you write. Like updating a status bar message in your case.
Updating the status bar message half a second later doesn't make a whole heckofalot of sense. What exactly happened during those 500 milliseconds that changed the way your program responds to events? You can call the Update() method of the StatusBar so the new message is visible, then call System.Threading.Thread.Sleep(500) to get what you want. You'll get away with it, the "Not Responding" ghost that Windows puts up takes your program going dead for several seconds.
But that doesn't make a lot of sense, nothing happened during that half second, the state of your program didn't change. It couldn't change, it was dead to Windows and not receiving any messages that would allow it to change state.
Well, that's about as far as I can take this. Please update your question and explain why you need to do this. Just in case: if you're contemplating this to fake doing something important for half a second, your user will not be impressed. She'll eventually notice your UI is dead for half a second without anything to show for it.
You have two choices:
Use a timer as you suggested. Split your method up into two methods, foo1 and foo2. Use the foo1 to start the timer and run foo2 in the callback.
Use a BackgroundWorker for running the entire function and use Thread.Sleep on the worker thread.
From your update it seems that the only thing you want to do is change a single field. I would definitely recommend the first method: using a timer. Starting a BackgroundWorker for this task is overkill and will just give you unnecessary extra work and complications.
Instead of pausing the UI directly for 500 ms, you can always use a BackgroundWorker. That will cause your callback to run in a separate thread, where you can use Thread.Sleep to pause it without blocking the UI. Then when you are done, just update the status bar with your new message.
More context to the question would be helpful.
Thread.Sleep(50) will pause the current thread for 50 milliseconds. If you're doing this in the UI thread, then yes, it will freeze the UI for 50 milliseconds. However, if you use a different thread to do this processing, then calling Sleep on that thread will pause it for 50 milliseconds without freezing your UI thread.
See Marc's answer to this question for an example on using a BackgroundWorker instance to do what you need.
In C# your best bet is to use the Timer and fire a callback.
In F# there is an awesome way to do what you want, see
F# async on the client side
which shows how to write straight-line code and have the language take care of the callbacks for you.
You need to allocate another thread. In that thread you Sleep(500) and change the needed data. Caution: you would need to use the original thread's dispatcher, because the data related to UI should be usually updated from the GUI thread.
On a regular basis I find myself writing little utility programs that use some loop which takes a while to process. Yet while the loop is going the form no longer refreshes so if you were to move the form, or move another window over it and off, the form would be blank until the loop finishes.
Now I know the correct way to deal with this is to use a background working to do the time consuming task on a separate thread. But I haven't quite got my head around the multi threaded stuff just yet.
So If I'm only going to use one thread what is the best thing to do on each loop to keep the contents of the form up to date. For example there may be a progress bar in the form.
I've seen and used various combonations of Form.Refresh(), Form.Update(), and Application.DoEvents() but was wondering what is the best way to deal with this?
You can fake it with Application.DoEvents() at different locations in the code, but you really should put the work in another thread.
Take it as an opportunity to get into threading, you will have to sooner or later.
The Bgw makes it easy: The DoWork event runs on another thread but ProgressChange and Completed are synchronized on the main thread.
Find a few examples and be careful when you use shared data inside DoWork.
My app monitors a directory where users can upload a file. When a new file is detected it is added to a queue. I have a timer that runs through the queue and determines if the file has finished uploading. If there are any files that are complete it will take the most recent and begin running a background task (using BackgroundWorker).
My problem is that I don't know how to handle the timer while the background task is running. For example, if the timer is set to 10 seconds and the background worker is still working I want the timer to skip execution of another background worker until its next iteration.
Also, the information for each task is stored in the Queue (a ListView control) and I pass the ListViewItem to the background worker. I'm curious if passing the ListViewItem has any side effects.
Thanks!
You could store ready-to-process files in another queue (like a Queue< string> ) and have the BgWorker continuously poll that Queue. You might get better performance too, less idle time. You will have to protect the Queue (with Monitor) and have the BgWorker use Monitor.Wait when the Queue is empty.
To get an idea, look for Marc Gravell's answer on this question.
Really hard to answer this without seeing the code you are talking about. However, if you have to synchronize multiple asynchronous events (detecting a file is downloaded, adding the file to a queue, processing the queue) I suggest creating a single BackgroundWorker that does all tasks. Then it is easy in your worker to test what state each step is at. I would avoid creating multiple threads and attempting to synchronize them, this is very very problematic.
I would also not store any background task information in a UI data structure (like a ListView control). Create a callback or event in your BackgroundWorker that will alert the UI when it needs to display something.
Is the BackgroundWorker.IsBusy Property what you're looking for?
The simplest thing you could do is do all the work (including checking the folder) inside your BackgroundWorker: Check if you have something to do, if yes, do it, if not, use Sleep(time) or WaitOne(time) to suspend the thread for some time.
I don't think you need a thread-safe queue here, because folder is being updated asynchronously anyway. So you only need one thread, but you need a way to stop it. That is why AutoResetEvent.WaitOne(time) would be better than Sleep(time) - you can signal the event from the main thread to end your background worker earlier.
On your Timer.Tick handler, check the BackgroundWorker.IsBusy property to determine if it's ready for another bit of work or not. If not, just skip giving it the work and wait until the next Tick.
You can create a thread queue in which you place work-to-do. Your background worker loops around pulling off items from the queue and perform the work.
Some things need to be considered:
The queue needs to be thread safe, and quite likely you'd want the backgroundworker to block if the queue is empty, and wake up when an item becomes available. Im sure somone has made such a nice queue already.
The items you post to the queue will be operated on in another thread(the backgroundworker). Make sure this is done in a thread safe manner (e.g. don't post items to the queue that both the main application and the background worker will alter)
Another and easier approach is to
Queue up items in your application. Kick off the backgroundworker one first time.
When you get the event that the backgroundworker is done, pick the next item off the queue and start the backgroundworker again with this item.
You still need to care about thread safety. When you've sent an item to the backgroundworker, make sure only the backgroundworker operates on it(e.g. if you're just sending it strings, send it a copy of said string instead)
I didn't quite follow you on the timer. If the background worker is finished you should get an event and you'll know it's finished, no need for a timer to check this.
I have a problem with interface lag in C#.
Since I'm still learning please be patient whilst I explain.
I have narrowed the problem to my timer object.
Basically my program queries a device through TCP/IP socket and outputs it to a textbox on screen.
Now I am polling the device for data every second which requires some logic to be buried within timer object and the following is what happens between ticks:
Increment a value.
Construct the 2 strings that represents the command to be sent to
the box (encapsulated in a function
Encode the command
Send command
Clear the byte array
Receive reply.
Could this be too much processing being done in the event handler? Every time I try to move the window during the polling session i.e. when the timer is running I get a very bad input lag.
The timer you are using is executing on the windows message thread. Therefore, while the polling is running the windows message queue is blocked. This isn't a problem with doing too much processing, most of the time the thread will be waiting for the TCP/IP response.
To fix this, you just have to do the do the work on a background thread and then update the UI on the UI thread.
There are a heap of different timers in the .NET framework that work in different ways, the one you are using works processed the timer event on the same thread, others work on background threads. Check this article out about the different timers.
You could also just use your current timer to invoke a BackgroundWorker component to do the work on the background thread. The main benefit of this is the the BackgroundWorker will do the work on a background thread, but will raise the work complete event on the UI thread so that it is simple to update the UI without having to worry about which thread you are on.
I think this is because you're trying to do work in your UI thread. Have your timer run in a background work thread.
It seems like there are a few things going on. First, you may be doing too much in your timer tick handler. How are you constructing the string and encoding the command? Can any of this be done once outside the tick handler or simplified in any way (using String.Format calls, for instance)? There are actually three different timers available in .NET, with different resolutions. Which timer are you using?
The biggest issue is the fact that your interval is 1 second. No matter what, that is a lot of processing overhead. Keep in mind that, for the most part, every time the interval is hit and the tick handler is invoked you are causing a context switch between threads. There is a bit of overhead involved in this (nothing which you can do anything about) and the more often you context switch the slower your performance appears.