Using threads to count the loops in C# events - c#

EDIT: It is not a listbox. My mistake. It is a list view.
I have a list view control that's driving me nuts. It is a multi-select list box, so if the user selects 5000 rows, then de-selects them by selecting a single row, the SelectedIndexChanged fires 5001 times. This causes my app to hang.
I'm trying to use threads to count the number of times that the event WOULD have fired, and then letting the last iteration do all the actual work.
Here's the code I started with. The big catch: I need the "do fancy calculations" to be in the same thread as the calling events due to items out of my control.
EDIT: I know that this code doesn't work. The Join() blocks the current thread which negates the entire purpose of creating the thread. My question is : How do I do something LIKE this.
My biggest problem isn't creating the thread. It's that my "do fancy" has to be in the same thread.
void IncrPaintQueue()
{
PaintQueue++;
Thread.Sleep(100);
}
int PaintQueue = 0;
private void SegmentList_SelectedIndexChanged(object sender, EventArgs e)
{
// We need to know how many threads this may possibly spawn.
int MyQueue = PaintQueue;
// Start a thread to increment the counter.
Thread Th = new Thread(IncrPaintQueue);
Th.IsBackground = true;
Th.Start();
Th.Join();
// if I'm not the last thread, then just exit.
// The last thread will do the right calculations.
if (MyQueue != PaintQueue - 1)
return;
// Reset the PaintQueue counter.
PaintQueue = 0;
// ... do fancy calculations here...
}

I remember solving this issue before:
A better way perhaps for you would be
to put a minimal delay in your
ItemSelectionChange Handler. Say --
50ms. Use a timer, Once the selection
changes, restart the timer. If the
selection changed more than once
within the delay period, then the
original is ignored, but after the
delay has expired, the logic is
executed.
Like this:
public class SelectionEndListView : ListView
{
private System.Windows.Forms.Timer m_timer;
private const int SELECTION_DELAY = 50;
public SelectionEndListView()
{
m_timer = new Timer();
m_timer.Interval = SELECTION_DELAY;
m_timer.Tick += new EventHandler(m_timer_Tick);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
// restart delay timer
m_timer.Stop();
m_timer.Start();
}
private void m_timer_Tick(object sender, EventArgs e)
{
m_timer.Stop();
// Perform selection end logic.
Console.WriteLine("Selection Has Ended");
}
}

A possible solution is to delay the work, so you know whether or not more events have fired. This assumes the order of the selections is not important; all that matters is the current state.
Instead of doing the work as soon as the event fires, set up a timer to do it a couple milliseconds after the event fires. If the timer is already running, do nothing. In this way the user should perceive no difference, but the actions will not hang.
You could also do the work on another thread, but have a flag to indicate work is being done. If, when the selection event fires, work is still being done you set a flag that indicates the work should be repeated. Setting 'repeat_work' to true 5000 times is not expensive.

I get the impression that you're trying to solve a problem through brute force. I would suggest trying a different event:
private void myListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (e.IsSelected)
{
// do your logic here
}
}
I would suggest avoiding creating threads if at all possible, since they have overheaad. I couldn't see from your example where there's any need for parallelism.

First, while you are properly synchronizing access to PaintQueue, I feel it was more by chance in this situation as opposed to design. If you have other code accessing PaintQueue on other threads, then you have a problem.
Second, this code makes no sense. You are spooling up a new thread, incrementing the value on that thread, and then waiting for 1/10th of a second. The thing is, the code that kicks off the thread is waiting on that thread to complete. Because of this, you are just waiting in the UI thread for nothing.
Even if you queue the SelectedIndexChange events, you aren't going to be able to prevent your app from hanging. The SelectedIndexChange event is going to fire every time that you select an item, and if the user selects 5000 items, then you need to process all 5000 events. You could give them a window (process every n seconds or whatever) but that's rather arbitrary and you put the user on a timer, which is bad.
What you should do is not tie the operation to the SelectedIndexChanged event. Rather, have the user select the items and then have them perform some other action (click a button, for example) which will work on the selected items.
Your app will still hang though if you have to process a number of items for a lengthy period of time on the UI thread, but at least selecting the items won't hang.

You don't really achieve any kind of concurrency by starting a new thread and then immediately Joining it. The only "effect" of the code above is that you method is run by another thread.
Additionally, if you want to use a background thread and safe the rather expensive cost of newing a thread, you should employ the thread pool.

Related

C# program using up too much CPU?

I have a program that starts constantly juggles between 3 separate timers.
The main thread of my application has a while loop which constantly checks if a global variable has been set to true and if it has, it will stop one timer and launch two other ones - one continuously, another to stop it automatically if it isn't commanded to stop for whatever reason.
This while loop has a condition of (1==1) so that it runs forever.
In the task manager (XP) I see that my program is using up 50% of cpu on a more or less idle system.
Is there a way to decrease that number by decreasing the speed of the while loop or something?
Thanks.
Is there a way to decrease that number by decreasing the speed of the while loop or something?
Just stop doing a busy loop. There are better ways of coordinating events between threads. Consider using Monitor.Wait/Pulse, or AutoResetEvent / ManualResetEvent. Basically, the thread that sets the global variable should signal that it's done so. Alternatively, if your main thread wouldn't be doing anything else, why not add a normal C# event so that whenever the variable is changed, the event is raised and the appropriate action can be taken?
Your program performs busy waiting, which is a bad practice. You should change your logic so that instead of looping, you block on some kind of synchronization primitive (also known as wait handle).
Blocking on a wait handle is not an option for the UI thread, so you would have to create three threads in total and implement the scheme like this:
The UI thread does not concern itself at all with what other threads to. No looping, no sleeping, no blocking.
The new "controller" thread would start the existing "worker" thread and then immediately block (e.g. on an event that is not signaled). It will remain in this state, without consuming CPU, until the event is signaled (i.e. the "worker" completes).
The "worker" thread would run its course and then signal the event.
Is there a way to decrease that number by decreasing the speed of the while loop or something?
Yes, you could insert a call to Thread.Sleep(n). With a granularity of ~20 ms.
But the far better option would be using a Waithandle.
Your main thread would Wait on the handle and the end of the timer code would signal it to wake up.
You need to sleep the threat for a given number of ms. Look at the Thread.sleep() function and place it within your while loop.
The easiest way to slow down a loop like this is to just add a System.Threading.Thread.Sleep(100); For every iteration the process will sleep for 100 ms and it will not use 50% cpu anymore.
You can use Threads instead of Timer it costlier than Thread. Or Please check the thread state of your time which stopped before start another. You can improve performance by cutting down your code logic.
Hope this will helps you. :)
While the answers here aren't wrong per-say, They don't really address a lot of issues with doing while(true) loops which is what while(1==1) is.
First of, even if the loop is running the entire time your application is in use, you will want to shit it down at some point, say when the user exits your application, because if you have a thread with a constant loop, even if the user closes the UI window, the process will remain until the thread exits (which is never in a while true loop) or until the user becomes wise and closes it from the task manager.
You COULD solve this by putting a true conditional in the while conditional check that references a accessible property outside the loop.
Example:
private bool RequestExit = false;
private Thread MyLoopThread;
private void MyLoop()
{
while (!RequestExit)
{
//Do stuff!
Sleep(1);
}
}
public void StartLoop()
{
RequestExit = false;
MyLoopThread = new Thread(MyLoop);
MyLoopThread.Start();
}
public void StopLoop()
{
RequestExit = true;
}
That is the bare-bones and doesn't even get into avoiding double launches or double shutdown events.
A much cleaner way would be to set an arbitrary interval that you want to pool at, 10ms or so should do just fine for pretty much any real time event, and trigger an method to fire at that interval.
private Timer DoStuffTimer;
private void DoStuffMethod(object obj = null)
{
//Do stuff!
}
public void StartLoop()
{
DoStuffTimer = new Timer(DoStuffMethod,null,10,10);
}
public void StopLoop()
{
DoStuffTimer.Dispose();
}

C# Method Statements Not executing in correct order

I seem to have a problem executing commands in the correct order, I have a method in my Program:
private void GenerateButton_Click(object sender, EventArgs e)
{
Statuslabel.Text = "Working...";
LongMethod();
//Call to another Method of another class which takes 15-20 seconds to execute
Statuslabel.Text = "Done";
}
the problem seems to be that instead of assigning "Working" to the status label and THEN calling the LongMethod, the Program seems to execute LongMethod() first, and then it changes Status Label's text to "Working" for a split second and then immediately changes it to "Done".
Oh, and the UI is locked up during the LongMethod() execution, because the Program is SingleThreaded.
I tried threads earlier, but for the life of me I couldn't get the syntax right, I tried:
Thread MyThread = new Thread(LongClass.LongFunction);
Thread MyThread = new Thread(new ThreadStart(LongClass.LongFunction));
Where LongClass is the class which contains LongFunction as a static method.
I will check out the background worker now.
You should execute LongMethod on another thread so that the UI thread doesn't block while it's running.
Remember, updating the UI is running code just like anything else. While your long-running method is running, that thread is not doing any of the tasks necessary to redraw the user interface. Changing a UI element does not stop everything and re-draw it because suppose you changed a thousand UI elements; you wouldn't expect a redraw after each one; you'd expect them all to happen at once, after you'd made all the changes.
Long story short, if you want to refresh the UI after the update but before the long-running code -- that is, you don't care about hanging the UI but you at least want it to update -- then insert a call that explicitly refreshes the UI.
Some have suggested "DoEvents" as a workaround. This can work, but it is super dangerous. For two reasons. First, suppose the user clicks a button twice. During the processing of the first click, you do a DoEvents, and so you then recurse and hey, now you have suspended the processing of the first button click so that you can process the second button click... and that can't be good.
Second, suppose you're processing an event, and you do a DoEvents, which causes you to start processing another event, and then while you're doing that, you do a DoEvents, and that causes you to start processing a third event... and this keeps going forever. When do you finish processing the first event? Potentially never. Remember "DoEvents" basically means "concentrate on what just happened at the expense of what you were already working on".
While I think Jason's answer to use another thread is the way to go, there is another "evil" option.
Statuslabel.Text = "Working...";
Application.DoEvents();
LongMethod();
Statuslabel.Text = "Done";

How to start a thread to keep GUI refreshed?

I have window with button which triggers lengthy processing. I put processing in a separate thread, but -- to my surprise -- it makes GUI frozen anyway. No control is refreshed, I cannot even move the window.
So the question is how to start the thread, so it won't interfere with GUI, i.e. so the GUI would always be up to date (while processing I change the data, and GUI displays some pieces of it)?
That is how I start thread currectly:
var thread = new Thread(doLearn);
thread.IsBackground = true;
thread.Start();
Edit 1
Jon:
I don't use any locks at all
No Join calling
The UI thread is left alone -- it simply sits there
The processing is a big loop with math operations, not even allocating memory, on UI side I have controls with binding (WPF) to data, like the number of current iteration of the main loop. It should be refreshed each time the main loop "ticks". The counter of the loop is a property which triggers OnPropertyChanged with each change (classic WPF binding).
Edit 2 -- Almost there!
Ok, so Jon hit the nail at the head (who is surprises? ;-D) -- thank you! The problem comes from changing the Counter. When I used instead the Counter, local counter the GUI was refreshed -- I mean I could move windows, but... I couldn't see display of the Counter.
What I have here -- a WPF GUI, with such data-binding
<TextBlock Text="{Binding Path=Counter"/>
and I have Counter property of course which on each change sends event PropertyChanged. One of the listeners is for sure GUI.
So, Jon answer is valid "the answer", but from good design POV not exactly, because if GUI part has to pull up the info about Counter and update the display every (let's say) 3 seconds, why would anyone use data binding? For me such approach invalidates data binding idea.
I could, theoretically, pass to the processing thread the GUI dispatcher, and do all the sending in GUI thread, and it could work (I didn't try it) but it would mean tight coupling of non-GUI part and GUI part.
So far, I have no idea how to do it "right" way. The best guess so far is to create TimerDispatcher but not at GUI side but inside the processing library, and update Counter value immediately but do all the sending from time to time (I didn't try it yet though).
Small remark: I have more properties binded actually, like IsRunning, which is changed at the beginning and at the end of processing. And those changes DO affect the display correctly -- but the Counter change triggers around 3000 notifications in 3-4 seconds. So it looks like jamming problem. I did another test -- I killed the data binding partially, so notifications were sent, but GUI was not "receiving" them -- but was listening to them. In such case the GUI was also frozen.
So, I am still listening to all advices -- thank you advance for sharing.
Edit 3
The saga continues here:
How to do the processing and keep GUI refreshed using databinding?
It should be fine as it is. Things which may be freezing your UI:
Are you locking within the UI thread, and locking on the same lock in your other thread?
Are you calling Join on the thread from your UI thread?
Are you doing some other heavy work in the UI thread?
If you could come up with a short but complete program which shows the problem, I'm sure we could help to fix it... but it certainly should be okay.
EDIT: Okay, now you've added this:
The counter of the loop is a property which triggers OnPropertyChanged with each change (classic WPF binding).
So you're updating the property from the non-UI thread? I would expect that to cause problems, because it will trigger UI changes from the wrong thread.
I suggest you take an approach such as:
Periodically update the counter via Dispatcher.BeginInvoke
Have the "UI counter" and the "worker counter" - and copy the value from the "worker counter" to the "UI counter" in the UI thread via a DispatcherTimer, essentially polling it.
There are numerous methods to run functions off the UI thread, but the easiest and generally most suitable is to look at the BackgroundWorker component. Many decent tutorials can be found. For example, here.
I put processing in a separate
thread, but -- to my surprise -- it
makes GUI frozen anyway.
I really hate to tell you, but then you did NOT put it into a separate thread. That simlpe.
There was a poster here that had a similar issue some time ago and through a mistake in his invoking code he basically had all processing before the thread started, with the thread jsut returning the result.
I faced the same situation, and solved it by two ways...
Use the thread in other class and invoke it in ur main application by creating Thread, either in its constructor OR in any method.
if u want do the it in same class, then create a Thread that call your function, and that function should invoke the Delegate.
See the examples:
public partial class Form1 : Form
{
private delegate void TickerDelegate();
TickerDelegate tickerDelegate1;
public Form1()
{
InitializeComponent();
}
//first solution
// This button event call other class having Thread
private void button1_Click(object sender, EventArgs e)
{
f = new FormFileUpdate("Auto File Updater", this);
f.Visible = true;
this.Visible = false;
}
// Second Solution
private void BtnWatch_Click(object sender, EventArgs e)
{
tickerDelegate1 = new TickerDelegate(SetLeftTicker);
Thread th = new Thread(new ThreadStart(DigitalTimer));
th.IsBackground = true;
th.Start();
}
private void SetLeftTicker()
{
label2.Text=DateTime.Now.ToLongTimeString();
}
public void DigitalTimer()
{
while (true)
{
label2.BeginInvoke(tickerDelegate1, new object[] {});
Thread.Sleep(1000);
}
}
}

C#: What if System.Windows.Forms.Timer interval was not enough for doing a job?

First, sorry for my bad english writing.
Suppose that we have a win form (C#) that has a timer. The timer interval has been set to 60000 milsec. So its tick event will be fired every 1 milute. Suppose we have written a method that handles tick event called Timer1_Tick. What if the job needs more that 1 minute to complete?
You've got several options, here's four I can think of:
Abandon the current job to start the new one. The big downside of this one is, of course, if the current job can't be stopped.
Wait for the current job to finish before starting the new one. This might leave you with a queue of pending jobs if each one takes more than a minute.
Don't start the new job. Let the current one finish and then wait for the next timer interval to start the new job.
Increase the interval between jobs. This is just putting off the problem.
There is no right answer. You'll have to work out what's best and works for your situation.
I'd go for #3 as my first solution.
Setup a flag that will allow you to check if the long running job has finished and only run the job if it has finished. Don't forget to reset the flag after finishing the long running job:
// field
private bool finishedWork = true;
public void Timer1_Tick(Object o, EventArgs e)
{
if (finishedWork)
{
finishedWork = false;
// do work
finishedWork = true;
}
}
Another option is to simply disable the timer between operations:
public void Timer1_Tick(Object o, EventArgs e)
{
if (finishedWork)
{
Timer1.Enabled = false;
// do work
Timer1.Enabled= true;
}
}
So set a flag when you start the job and check the flag when the timer fires. If the flag is set, do nothing in the timer handler. Remember to clear the flag when the job completes.
Are you spinning off a worker thread to do the job?
Another timer event will likely be queued, causing Timer1_Tick to be called again almost immediately after it returns. (IIRC, though, timer ticks are one of the lowest priority messages, so it'll probably handle any other messages it's had queued up to that point first, except maybe paint messages).
Note, if your function takes longer than 2 minutes to run, it's possible (read: likely) that only the latest tick will be in the queue.
If your tick processing takes longer than the timer interval, you should look into raising the interval. Either way, you should probably be doing the work in a background thread and making sure you don't start another thread if the last tick's task isn't done. Otherwise you could end up with hordes of threads all slowing each other down til your program collapses under its own weight.
Store the current state of the process in a field or property and start the process only if the state is no "running".
Disable the timer at the start of Timer1_Tick and then enable it again afterwards?
There are multiple types of Timers in .Net: One is in a System.Timers namespace, another is in System.Windows.Forms namespace and another in System.Threading.
The System.Windows.Forms.Timer control is based on UI thread and message loops, meaning it will queue the timer events and if your handler exceeds the interval, it will be called immediately after ending.
The other two timers are based on threading, and are very accurate. They will reenter you handler after the time elapsed.

BackgroundWorker used within collection items

I used a Backgroudworker to do some work in order to do some time consuming tasks.
public void ConnectDataProvider()
{
bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
Another method starts the background worker:
public void StartPolling()
{
bgw.RunWorkerAsync();
}
Then I did the event handling:
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// do it over again
StartPolling();
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// do work
WriteData();
}
As you can see, I started the worker over on completion. Now this works for a single backgroundworker.
Now I want a collection, and each item should perform this task. However with the concept above it will just keep on running in the first worker started, as it starts the worker over. I'm thinking, maybe a Timer in combination could solve the situation to give the other worker threads way.
Is the BackgroundWorker still a good choice? Is it common to reuse the BackgroundWorker like I did?
EDIT 1: To clairify: The problem I'm facing is, that I need manage the collection each with their own BackgroundWorker. I was thinking about a timer, to set off request periodically from each item. This is where I'm stuck.
EDIT 2: See my own answer, I didn't solve this issue, but found that I can go along with timers to get what I wanted.
EDIT 3: To clarify (another try, I'm not good at that) what I wanted to achieve: I've got tracking objects, for gps tracking. I want to track a whole bunch of them, so one object per tracking device. They all need to be polled frequently. Ihad a BackgroundWorker set up for a single test object. I liked they way the Backgroundworker would tell me when it's done. But I couldn't get it working with all of the tracking objects.
Now every tracking object has its own timer. This timer spawns a new thread and does the time consuming work (which I named DoWrite). No BackgroundWorker needed, as I dispose the timer and then create a new timer. That's all it does.
How many of these might there be? You should be careful of creating a 1:1 relationship between items in a collection and threads. Another coder might come along and expand this collection more than you planned.
For things like this I usually like to use just the one thread, and a queue - so the events just put the work that needs to be done in a ConcurrentQueue, and the thread starts if not running, and churns through the queued work until it's out of things to do, and dies. The next time more work comes in the event will check if the thread is running and start it.
It's cheaper because if there's a lot going on, you run just the one thread instead of stopping and starting a lot of them, or if there's very little going on, the one thread is almost never running.
Your solution would look more logical if you just put a while() loop in Dowork(), maybe with a little Sleep().
And then there would be no objection against running multiple Bgw's, although you may not see a great speed benefit.
You can do exactly what you describe--just make sure that you pass the reference to the relevant background worker to StartPolling, thusly:
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// do it over again
StartPolling((BackgroundWorker)sender);
}
public void StartPolling(BackgroundWorker worker)
{
worker.RunWorkerAsync();
}
Then obviously, you need to manage the collection of BackgroundWorker's accordingly.
Why don't you use the progresschanged event? You could use the userstate object for passing data.
In do work just pool the devices, and in process changed send the data to the UI thread.
Do it in a endless while and use cancel to stop that thread.
Regards.
When you have multiple time consuming tasks to be executed in the same time, I suggest you to use Thread Pool
http://msdn.microsoft.com/en-us/library/ms973903.aspx
Since nobody did it so far, I'll throw in the timer approach. I tried to combine the two (BackgroundWorker and Timer), but that didn't make sense.
I wanted a mechanism to allow multiple instances to request data by thread. Also, I wanted some interval in between.
So after trying around, I figured I could get along with a Timer-approach only:
public void ConnectDataProvider()
{
timer = new Timer(new TimerCallback(tCallback), null, 0, Timeout.Infinite);
}
private void tCallback(object state)
{
timer.Dispose();
// time consuming task
WriteData();
timer = new Timer(new TimerCallback(tCallback), null, 5000, Timeout.Infinite);
}
That was what John Saunders suggested on a similar (but different) problem. It seems to do the job. The WriteData() has a synchronous HttpWebRequest, so it can handle a timeout.
My question now is: How expensive is the new instantiation of the timer object? By how expensive I mean: Are there better ways to achieve that?
Note: The asynchronous approach of the WebRequest won't work, I tried that. I have no clue so far, if that is a manner of the server.

Categories