C# Timer won't run down to form freezing - c#

so when i try and press "button 2" I expect two things to happen a)"dowsomething" is suppose to do its thing in the "now" class. b) Whilst its doing something i want it to count how long that something takes. However because "dosomething" is program hungry Form1 freezes and it wont run the timer. Im a bit of a rookie at c# so I wouldn't know how to run it in the background. So any outside the box ideas? Thanks.
int time = 0;
private void button2_Click(object sender, EventArgs e)
{
timer1.Start();
nowthen now = new nowthen();
now.dosomething(withthis); //This task is program hungry and causes the form to freeze
timer1.Stop();
time = 0;
}
private void timer1_Tick(object sender, EventArgs e)
{
time = time + 1;
label2.Text = time.ToString();
label2.Refresh();
}

In Windows Forms, all of your UI stuff runs on one thread. That includes the timer - the timer is implemented behind the scenes with windows messages.
Your question is actually two questions:-
How can I time an operation in C# / Windows forms?
How to time something depends on the precision you're looking for. For accuracy in the region of +/- 10ms then you can use Environment.TickCount - store it's value before your operation, then get the value again after, and subtract the stored value - and you have your duration.
More precise is the Stopwatch class in System.Threading - see http://www.dotnetperls.com/stopwatch
How can I run a task "in the background" ?
To run your operation in the background, you need to run it in a different thread. The easiest, designed friendly (but perhaps not all that flexible way) is to use the BackgroundWorker component. This wraps using a worker thread to do an operation for you. See http://www.dotnetperls.com/backgroundworker for a good explanation of how to do that.
More advanced, and more flexible, is to create your own thread to do the work. However, that will create some important issues to consider around how to syncronize what's going on - as soon as you start your thread, your method call finishes (it's asyncronous) and you need to have a mechanism for notifiying your UI code that the process has finished. This example seems as good as any on how to create your own thread: http://www.daveoncsharp.com/2009/09/create-a-worker-thread-for-your-windows-form-in-csharp/

For .NET 4 use:
Task.Factory.StartNew((Action) delegate()
{
// this code is now executing on a new thread.
nowthen now = new nowthen();
now.dosomething(withthis);
// to update the UI from here, you must use Invoke to make the call on UI thread
textBox1.Invoke((Action) delegate()
{
textBox1.Text = "This update occurs on the UI thread";
});
});

If you just want to time how long something takes, use System.Diagnostics.Stopwatch.
Stopwatch sw = Stopwatch.StartNew();
nowThen = new nowThen();
no.dosomething(withthis);
sw.Stop();
// you can get the time it took from sw.Elapsed
That won't, however, update a label with the elapsed time.

I guess I'll throw this in too, although it's not as elegant looking as #paul's solution.
timer1.Start();
var bw = new BackgroundWorker();
bw.DoWork += (s, e) => { now.dosomething((myArgumentType)e.Argument); };
bw.RunWorkerCompleted += (s, e) => { timer1.Stop(); };
bw.RunWorkerAsync(withthis);
This starts your timer, creates a new BackgroundWorker thread, tells it what to run in the DoWork method (dosomething runs in a separate thread), then stops the timer in the RunWorkerCompleted method (after dosomething is finished, control returns to the main thread in RunWorkerCompleted).

Related

Timer being interrupted

I have a problem with the Timer in a Windows Forms app. The archiver that needs the Timer to note the time of archiving. However something is interrupting the timer?
I suspect it is the streams. Any advice on what could cause the timer to be interrupted?
public partial class Form1 : Form
{
int timerCounter = 0;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
timer.Interval = 1000;
timer.Enabled = true;
}
public void button2_Click(object sender, EventArgs e)
{
timer.Start();
timer.Tick += new EventHandler(timer1_Tick);
// code for archiving, streams
timer.Stop();
MessageBox.Show("Archive was created! :)");
}
public void timer1_Tick(object sender, EventArgs e)
{
this.label7.Text = (++timerCounter).ToString();
}
}
The Windows Forms timer is not multi-threaded. That means, the tick event only fires when the program is idle (receives messages through its message queue). In your program this doesn't seem to be the case. You can easily check this: If your UI is responsive during the archiving process, then the Forms.Timer runs also and the problem is somewhere else. If it is not responsive, then the form (and the timer as a consequence) is blocked (no messages in the application's message queue are processed).
There are two ways out of this:
To do what you want to achieve, you can use System.Timers.Timer or System.Threading.Timer, as they run asynchronously in the background. The UI still won't update (the timer method would stop), however, as the UI is still blocked (see above).
The other way is to use a background worker for the archiving process (this then runs in another thread). The UI and the timer keep responsive.
First of all you should to know that long running operation should be performent in another than UI thread. So, you create a proccessing thread which do archiving itself and also it notifies UI by using Control.Invoke method. msdn description of Control.Invoke
Initially i thought that you are performing your archiving in the background thread. If it is not so - you should consider using BackgroundWorker for executing the operation in the background (here's some examples).
Here is the simpler solution, though:
Try to add Application.DoEvents() in your button2_Click handler (I guess you are waiting for 'streams' to finish the archiving). For timer to fire and for label7 to redraw its new text value the redraw event should be processed.
The use of timer here is unnecessary why don t you just use TimeSpan
public void button2_Click(object sender, EventArgs e)
{
DateTime startTime = DateTime.Now;
// code for archiving, streams
TimeSpan diff = DateTime.Now - startTime;
MessageBox.Show("Archive was created! in " + diff.TotalSeconds + " seconds.");
}

Simple task without freezing the gui

I came across with a little problem. I have two threads one that executes a loop that needs to return/send a number to the GUI's thread every time. For this I use the BackGroundWorker and the ReportProgress .
Let say something like that:
I have a BackGroundWorker that executes (DoWork) a simple loop that counts from 0 to whatever. Every entry to the loop I send the counter using the ReportProgress event to the GUI's thread that will print the counter's value.
void worker_DoWork(object sender, DoWorkEventArgs e)
{
int count = 0;
BackgroundWorker Worker = (BackgroundWorker)sender;
while (count < 10000000)
{
Worker.ReportProgress(count);
count++;
}
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
txt.Text = e.ProgressPercentage.ToString();
}
Now, this opretion freezes the GUI.
I understand that the ReportProgress is invoking the ProgressChange handler at the thread that created the BackGroundWorker , So I think the loop is executeing so fast so the GUI's thread isn't succeeding to print the values as required.
What Can I do to perform a task like that without freezing the GUI?
I heard of the Dispatcher but I don't really sure for what it uses for.
The problem is that you are calling reportProgress every time something changes. You should call it only when you "need" to report progress. See MSDN http://msdn.microsoft.com/en-us/library/ka89zff4.aspx.
Change your dowork to something like this:
while (count < 10000000)
{
if ((count % 1000) == 0)
Worker.ReportProgress(count);
count++;
}
This will call ReportProgress after each 1000 processed items and therefore not put unnecessary load to your GUI thread
You example code is attempting to update the GUI at a much faster rate than the GUI can process the update notification messages, so flooding the GUI Windows message queue with gunge and preventing it handling other messages - GUI freeze.
Monitoring the progress of high-rate operations in a non-GUI thread is one of the few times when polling is the better solution. Use a Forms.Timer event to read and display a 'currentProgress' value, perhaps returned by a method of the thread. 500ms is a reasonable timer value - human users cannot keep up with a changing integer value in an edit/text box at a rate much faster than that.
'Ideally', the read/write of the currentProgress value should be locked up, perhaps with an atomic op, but if you're only reading an int every 500ms, you probably don't even need that if the 'real' functionality of the thread means that the progress count is very unlikely to be continuously cached in a register.
What Can I do to perform a task like that without freezing the GUID? :
Using dispatcher made me assume you're using WPF, anyways, it would be :
void worker_DoWork(object sender, DoWorkEventArgs e)
{
int count = 0;
BackgroundWorker Worker = (BackgroundWorker)sender;
while (count < 10000000)
{
Worker.ReportProgress(count);
count++;
}
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Dispatcher.BeginInvoke((Action)(() => { txt.Text = e.ProgressPercentage.ToString(); }));
}
Calling the Dispatcher.BeginInvoke causes the given Action to actually be executed on the UI thread, making sure no Exception is thrown for the cause of a thread other than the UI thread accessing a UI element.
Also, you might try this, just as an alternative by using a task.

Firing a sound with a timer in a backgroundworker, wp7 phone app

I am hitting a wall and have come here hoping you guys can help me out with the following:
I am designing a wp7 app where I am having sounds fire off periodically (every 700 ms). I want these sounds to play on another thread than the UI thread. Thus, I cannot use a dispatch timer because the UI thread will be heavily used in the meantime while these sounds fire.
In looking at this problem, I made a backgroundworker with a Thread.Sleep(700) command. This works, but as one may expect it can take longer than 700 ms to fire off a sound. So sometimes I hear delays.
So I turn to you guys -- How can I get as close to a firing of a sound every 700 ms in a backgroundworker or another thread? Is a Timer a wise idea?
Here is some code to better illustrate:
private void RunBackgroundWorker()
{
backgroundWorker = new BackgroundWorker ();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += new DoWorkEventHandler(StartSounds);
backgroundWorker.RunWorkerAsync();
}
public void StartSounds(object sender, EventArgs e)
{
for (currentsoundchoice = 0; currentsoundchoice <= max; currentsoundchoice ++)
{
if (backgroundWorker.CancellationPending == true)
{
backgroundWorker.CancelAsync();
currentsoundchoice = max + 1; //just to ensure it stops.
}
else
{
Time_Tick();
if (max == 12)
currentsoundchoice = -1; //repeats the loop when it reaches max.
}
}
}
void Time_Tick()
{
Thread.Sleep(700);
FrameworkDispatcher.Update();
switch (sounds)
case 0: //code
break;
// ETC, So forth.......
}
I heard that using a Timer is also a good way to go about this, but is it possible to run a timer in a backgroundworker, and if so, how would it be structured? More importantly, would it allow me to get as close to the 700 ms firing time I desire without any audible delays?
Thank you.
BackgroundWorker is the wrong choice here. It is designed to allow you to perform expensive work on a background thread and then synchronize the results back to the UI. You do not need any synchronization. Moreover, you need the work to occur at a regular interval - not as a one-off task.
A Timer would be much more suited. It would allow you to run your logic every 700ms and to remove the nasty Thread.Sleep() call you have in your current code. The Timer will use a background thread just like BackgroundWorker does.
Note, however, that it can only guarantee that it won't run before 700ms has elapsed. If you're absolutely hammering the device, for example, it may struggle to run your code on a regular interval and you may notice lag.

Reusing a BackgroundWorker, cancel and wait for it

Suppose you have a search textbox and have a search algorithm attached to the TextChanged event, that runs with a BackgroundWorker. If there comes a new character in the textbox, i need to cancel the previous search and run it again.
I tried using events in between the main thread and the bgw, from this previous question, but I still get the error "currently busy and cannot run multiple tasks concurrently"
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
private AutoResetEvent _resetEvent = new AutoResetEvent(false);
private void txtSearch_TextChanged(object sender, EventArgs e)
{
SearchWithBgw();
}
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
void bgw_Search_DoWork(object sender, DoWorkEventArgs e)
{
Search(txtSearch.Text, e);
}
private void Search(string aQuery, DoWorkEventArgs e)
{
int i = 1;
while (i < 3) // simulating search processing...
{
Thread.Sleep(1000);
i++;
if (bgw_Search.CancellationPending)
{
_resetEvent.Set(); // signal that worker is done
e.Cancel = true;
return;
}
}
}
EDIT To reflect answers. DonĀ“t reuse the BackgroundWorker, create a new one:
private void SearchWithBgw()
{
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
bgw_Search = new BackgroundWorker();
bgw_Search.WorkerSupportsCancellation = true;
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
bgw_Search.RunWorkerAsync();
}
When the _resetEvent.WaitOne() call completes, the worker thread isn't actually done. It is busy returning from DoWork() and waiting for an opportunity to run the RunWorkerCompleted event, if any. That takes time.
There is no reliable way to ensure the BGW is completed in a synchronous way. Blocking on IsBusy or waiting for the RunWorkerCompleted event to run is going to cause deadlock. If you really want to use only one bgw then you'll have to queue the requests. Or just don't sweat the small stuff and allocate another bgw. They cost very little.
Create a new background worker if the old one exists.
private void SearchWithBgw()
{
// cancel previous search
if (bgw_Search.IsBusy)
{
bgw_Search.CancelAsync();
// wait for the bgw to finish, so it can be reused.
_resetEvent.WaitOne(); // will block until _resetEvent.Set() call made
BackgroundWorker bgw_Search = new BackgroundWorker();
bgw_Search.DoWork += new DoWorkEventHandler(bgw_Search_DoWork);
}
// start new search
bgw_Search.RunWorkerAsync(); // error "cannot run multiple tasks concurrently"
}
Also I know you put fake code in, but you want to make sure you set _resetEvent when the code completes normally too.
Do not reuse a Backgroundworker. It is a cheap resource, it is not a Thread.
make sure your Bgw code stops, yours looks OK. The Bgw will release the Thread to the pool.
but in the mean time, create a new Task/Bgw for a new job.
You may want to unsubscribe your Completed event from the old Bgw.
I think you should consider not cancelling the background worker.
If you cancel requests and the user types faster than your server returns queries, he will not see suggestions until he is finished typing.
In interactive scenarios like this, It could be better to show responses that run behind with what the user's typing. Your user will know he can stop typing if the word he has in mind is your suggestions list.
This will be also better for your server when it is busy, because instead of many cancelled requests, who will cost something but that are ultimately not shown, there will be fewer requests whose response you actually use.
I ran into similar issues with (3d) rendering applications, where the beginner's mistake is to cancel and rerender on every mousemove. This lead to a lot of computation and little interactive feedback.

System.Timers.Timer delay hangs application

I have an issue with the System.Timers.Timer object. I use the timer object to perform a task at regular intervals. In the timer constructor I call the method doing the work ( DoTimeCheck() ), to ensure that the task is run once at startup also. The work (at regular intervals) is done in a BackgroundWorker.
I call the timer with this:
UpdaterTimer ut = UpdaterTimer.UpdaterTimerInstance;
My problem is that I need to delay the first run of the task with 3 minutes(the one that runs at application startup). Subsequent runs (Elapsed event) should run without delay. I thought of doing this by calling
System.Threading.Thread.Sleep(TimeToDelayFirstRunInMiliseconds);
but this fails, because it also hangs the UI of the app (main thread) making it unusable. How can I delay the first run of DoTimeCheck() without hanging the UI?
The code of the timer is below. If the issue is not presented in a clear manner please let me know and I will edit. Thank you in advance.
public sealed class UpdaterTimer : Timer
{
private static readonly UpdaterTimer _timer = new UpdaterTimer();
public static UpdaterTimer UpdaterTimerInstance
{
get { return _timer; }
}
static UpdaterTimer()
{
_timer.AutoReset = true;
_timer.Interval = Utils.TimeBetweenChecksInMiliseconds;
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Start();
DoTimeCheck();
}
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
DoTimeCheck();
}
private static void DoTimeCheck()
{
//... work here
}
}
One way of doing this would be to give the Timer Interval an initial value (e.g. 3 minutes). Then, in your Elapsed event handler, you could change the interval to your regular value which will be used from then on.
_timer.Interval = Utils.InitialCheckInterval;
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_timer.Interval == Utils.InitialCheckInterval)
{
_timer.Interval = Utils.RegularCheckInterval;
}
DoTimeCheck();
}
It appears (although you've not shown that code) that you're calling Sleep(TimeToDelayFirstRunInMiliseconds); on the main/GUI thread, so that's what's causing your UI thread to hang. Instead, you should set your timer to be delayed by 3 minutes on the first run, then once it runs you change the timer again to run at the frequency you desire for all the subsequent runs.
Your UI resides on the same thread, so when you put the thread to sleep, it will cause your UI to hang as well. You need to run the timer on a different thread.
You're already using timers fine it seems. Just use another one to do a three minute delay before you start up your other timer.
timer = new Timer();
timer.AutoReset = false;
timer.Interval = 3*60*1000;
timer.Elapsed += startOtherTimerMethod;
timer.Start();
Edit: I should note that this is much the same as Peter Kelly's answer except that his solution is more elegant since it uses just one timer, no extra methods and takes advantage of the fact that the timer is changeable between runs. If you liked this answer, you'll love his. ;-)
Your UI needs a seperate thread, currently you are also sleeping the UI. Check this post.
You should not use thread.sleep in this situation you should use the winforms control
BackgroundWorker which never locks the main UI. You can write your logic there.
example here:
http://www.knowdotnet.com/articles/backgroundworker.html
Use a System.Threading.Timer - the constructor takes a parameter for the delay of the first run and an interval for the subsequent runs.

Categories