Why doesn't the Timer Start in Program? - c#

I have a simple C# program (done in MS visual Studio 2010).
It is a windows form with a single button on it. As you can see its just a simple program but Im stuck on it.
I am trying to understand C# timers and global variables in C#.
I wanted it to do the following, when the button is pressed
a message box appears (every second) displaying the number
of seconds since the button was pressed.
It supposed to working by setting a variable starttimer to true (in one function) and in another function when that starttimer equals true is detected it shows the time in seconds in the message box.
However it it doesn't seem to detect that starttimer equals true in the other function. The purpose of the starttimer variable is to detect the button press for using to start showing the message box every second.
So what the easiest way to fix this program?
PS When the program is run without the code for starttimer it does show the message box every second (when the program is started).
A picture of the program windows form is shown -as you can see it really simple-just one button.
namespace timerprogram
{
public partial class doeverysecond : Form
{
int thetimeinsecs = 0;
bool starttimer = false;
private void Form1_Load(object sender, EventArgs e)
{
}
private void customfn(object source, ElapsedEventArgs e)
{
if (starttimer == true)
{
thetimeinsecs = thetimeinsecs + 1;
MessageBox.Show(thetimeinsecs.ToString());
}
}
public doeverysecond()
{
{
{
System.Timers.Timer mytimer = new System.Timers.Timer();
mytimer.Elapsed += new ElapsedEventHandler(customfn);
mytimer.Interval = 1000;
mytimer.Start();
}
}
}
private void button1_Click(object sender, EventArgs e)
{
starttimer = true;
}
}
}

So what the easiest way to fix this program?
Actually it would be to hit the button, so that the variable starttimer is set to true and you will be able to see the MessageBoxevery second. You program works!
Beside that it would be good to bring more structure into your program, by having a method that starts the timer with a button click:
private void button1_Click(object sender, EventArgs e)
{
if(!mytimer.Enabled) // this will prevent a double start
{
starttimer = true;
mytimer.Start();
}
}
The constructor should get rid of the timer start line:
public doeverysecond()
{
{
System.Timers.Timer mytimer = new System.Timers.Timer();
mytimer.Elapsed += new ElapsedEventHandler(customfn);
mytimer.Interval = 1000;
}
}
Division of responsibilities is important here. The constructor is for initialisation of variables. So this is his job. The Button starts the timer.
The if-clause to check if (starttimer == true) is actually not necessary, since you never call this method from somewhere else in your code.
And setting the boolean variable to true does not start the timer. It is only a flag!

Timers can be a bit weird, but it looks like your main issue is that mytimer is within a method scope, meaning that when that method ends, mytimer is cleaned up by the garbage collector and it stops running. This happens because when the method ends, there is no way to access mytimer again from elsewhere in the code. To save on memory, .NET cleans up after you, but in this particular case it's not smart enough to know that you are actually still using the timer.
The solution is quite simple, put mytimer at the class level. You can also get rid of the starttimer bool, as now you can check the timer itself to see if it's running.
You could do something like:
namespace timerprogram
{
public partial class doeverysecond : Form
{
//Timer is class level, so it sticks around and can be called from
//multiple methods
System.Timers.Timer mytimer = new System.Timers.Timer();
int thetimeinsecs = 0;
private void Form1_Load(object sender, EventArgs e)
{
//Setup the timer, but don't start it
mytimer.Elapsed += new ElapsedEventHandler(customfn);
mytimer.Interval = 1000;
}
private void customfn(object source, ElapsedEventArgs e)
{
//We can check the timer itself to see if it's running!
if (mytimer.Enabled)
{
thetimeinsecs = thetimeinsecs + 1;
MessageBox.Show(thetimeinsecs.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
//Start the timer!
mytimer.Start();
}
}
}
Oh, and with regards to that whole 'scope' thing. In C#, a scope is basically something in between a { and a }. In methods and normal code, variables created inside a scope cannot be seen by code outside the scope. That's why you get a compiler error if you do something like:
if(something)
{
int x = 5;
}
x = x + 5; //x doesn't exist here! It disappears at }
You can access things from outside a scope inside a scope though, so
int x = 0;
if(something)
{
x = 5; //x exists in an outside scope
}
x = x + 5; //This is fine
Anything at the class scope can be seen by all methods inside a class, which is why the timer now sticks around. Class scope is slighty different though, in that you can see things in other classes if they have public before them. The same goes for methods (Note that all your methods have 'private', so outside classes can't call them. Change them to public and they can!)

Need to enable the timer.
myTimer.Enabled = true

Related

Calling a method after set amount of time and/or aborting thread issues

So I've got an application that employs a filesystemWatcher and triggers an event just fine. The FSW will trigger a bunch of times pretty close together. I want to create a function that triggers say an hour after the last time the FSW was triggered.
I first tried using a backgroundworker: (All code is shortened for clarity)
namespace Devo
{
public partial class Form1 : Form
{
BackgroundWorker bw = new BackgroundWorker();
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync(); //this is to, in a way, reset the timer for the delayed method.
}
//do a lot of stuff
bw.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Stopwatch sw = new Stopwatch();
sw.Start();
while(sw.ElapsedMilliseconds < 180000)
{
if (bw.CancellationPending == true)
{
sw.Stop();
sw.Reset();
e.Cancel = true;
return;
}
}
sw.Stop();
sw.Reset();
DelayedMethod();
}
}
}
This didn't work as the second time bw.RunWorkerAsync() was called it was apparently busy, even though the call to bw.CancelAsync().
My next attempt involved a regular thread as I read somewhere on SO (can't find the link now) that one could not "restart" a backgroundWorker as I am trying to do.
The thread attemp is nearly identical but I thought I'd try in since there might be some constraints within the backgroundWorker that is not present in a regular thread. I thought.
namespace Devo
{
public partial class Form1 : Form
{
Thread PWC_counter_thread = new Thread(PWC_Counter);
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (PWC_counter_thread.IsAlive)
PWC_counter_thread.Abort();
//do a lot of stuff
PWC_counter_thread.Start();
}
static void PWC_Counter()
{
Thread.Sleep(180000);
DelayedMethod();
}
}
}
But this gave me the same error. On the second call to PWC_counter_thread.Start() is was busy.
I'm assuming that a race condition is not present as the second thread waits for, in this example, 3 minutes, and the initial FSW method takes a good full second to execute, therefore I believe that the call to .Abort() and .CancelAsync() both are done before their respective methods are completed.
Now for the questions:
Is it possible to restart a thread in the fashion I am trying? If so, what am I doing wrong?
Should I delay my method call in another way? If so, tips?
EDIT/UPDATE/SOLUTION
I never got starting and stopping a thread to work as I wanted so I found another solution to my situation.
The situation was that I had a second thread that worked as a sort of timer where it would call a method after a set amount of time. My first thread did some work and upon finishing it would start the second thread. If the first thread got fired up again before the timer-thread had finished it was supposed to kill the thread and restart it.
This proved, for me, to be difficult to get the way I wanted. So I instead took another approach towards my wanted end result. Instead of restarting the thread I simply restarted the stopwatch that my second thread was using as a counter. This gave me the result I wanted. It's probably bad practice but it works.
In your BackgroundWorker example you probably have an issue with racing. CancelAsync(), as its name implies, is an asynchronious call, meaning that BackgroundWorker does not stop working immediately and it might still work when try to restart it. To avoid that, you should subscribe to RunWorkerCompleted event and wait for it to fire before calling bw.RunWorkerAsync(); again. For example:
public Form1()
{
bw = new BackgroundWorker();
bw.RunWorkerCompleted += OnCompleted;
}
private BackgroundWorker bw;
private ManualResetEvent completed = new ManualResetEvent(false);
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
completed.Set();
}
private void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
if (bw.IsBusy)
{
bw.CancelAsync();
completed.WaitOne();
}
//do a lot of stuff
completed.Reset();
bw.RunWorkerAsync();
}
You have multiple issues with your Thread-based example.
You should never call Thread.Abort(). Instead, you should implement a cancellation mechanism, similar to that of BackgroundWorker. Make a bool field (_isCancelled or something) and check it periodically in thread delegate.
You can not reuse a Thread object. You should always create a new one.
You would be best off encapsulating this in a class, and use a System.Threading.Timer to detect the inactivity.
Here's an example I put together. The idea is that you create an InactivityDetector with the appropriate inactivity threshold (an hour in your case) and a callback method that will be called when that period of inactivity is exceeded.
You have to call InactivityDetector.RegisterActivity() whenever activity is detected (e.g. in your case a file creation is detected).
Once the inactivity callback has been issued, it will not be called again until RegisterActivity() has been called again (this prevents multiple callbacks for the same period of extended inactivity).
Your code would pass DelayedMethod for the inactivity Action delegate.
Note that the callback is on a separate thread!
(Also note that I didn't put in any parameter validation, to keep the code shorter.)
using System;
using System.Threading;
namespace ConsoleApp1
{
sealed class Program
{
void test()
{
using (var inactivityDetector = new InactivityDetector(TimeSpan.FromSeconds(2), inactivityDetected))
{
for (int loop = 0; loop < 3; ++loop)
{
Console.WriteLine("Keeping busy once a second for 5 seconds.");
for (int i = 0; i < 5; ++i)
{
Thread.Sleep(1000);
Console.WriteLine("Registering activity");
inactivityDetector.RegisterActivity();
}
Console.WriteLine("Entering 3 second inactivity");
Thread.Sleep(3000);
inactivityDetector.RegisterActivity();
}
}
}
static void inactivityDetected()
{
Console.WriteLine("Inactivity detected.");
}
static void Main(string[] args)
{
new Program().test();
}
}
public sealed class InactivityDetector: IDisposable
{
public InactivityDetector(TimeSpan inactivityThreshold, Action onInactivity)
{
_inactivityThreshold = inactivityThreshold;
_onInactivity = onInactivity;
_timer = new Timer(timerCallback, null, (int)inactivityThreshold.TotalMilliseconds, -1);
}
public void RegisterActivity()
{
_timer.Change(-1, -1);
_timer.Change((int)_inactivityThreshold.TotalMilliseconds, -1);
}
private void timerCallback(object state)
{
_timer.Change(-1, -1);
_onInactivity();
}
public void Dispose()
{
_timer.Dispose();
}
private readonly TimeSpan _inactivityThreshold;
private readonly Action _onInactivity;
private readonly Timer _timer;
}
}

How to use a timer to wait?

I am trying to delay events in my method by using a timer, however i do not necessarily understand how to use a timer to wait.
I set up my timer to be 2 seconds, but when i run this code the last call runs without a 2 second delay.
Timer timer = new Timer();
timer.Tick += new EventHandler(timer_Tick); // Everytime timer ticks, timer_Tick will be called
timer.Interval = (1000) * (2); // Timer will tick evert second
timer.Enabled = true; // Enable the timer
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
timer.Start();
label1.Text = "second";
}
So when i click my button, it immediately shows label1 as "second", as opposed to changing to "first", waiting 2 seconds, then changing to "second". I have read lots of threads here about using timers instead of thread.sleep, but i cannot seem to find/figure out how to actually implement that.
If you're using C# 5.0 await makes this much easier:
private async void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
await Task.Delay(2000);
label1.Text = "second";
}
timer.Start() just starts the timer but immediately returns while the timer is running in the background. So between setting the label text to first and to second there is nearly no pause. What you want to do is wait for the timer to tick and only then update the label again:
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
label1.Text = "second";
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
timer.Start();
}
Btw. you should not set timer.Enabled to true, you are already starting the timer using timer.Start().
As mentioned in the comments, you could put the timer creation into a method, like this (note: this is untested):
public void Delayed(int delay, Action action)
{
Timer timer = new Timer();
timer.Interval = delay;
timer.Tick += (s, e) => {
action();
timer.Stop();
};
timer.Start();
}
And then you could just use it like this:
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
Delayed(2000, () => label1.Text = "second");
}
Tergiver’s follow-up
Does using Delayed contain a memory leak (reference leak)?
Subscribing to an event always creates a two-way reference.
In this case timer.Tick gets a reference to an anonymous function (lambda). That function lifts a local variable timer, though it's a reference, not a value, and contains a reference to the passed in Action delegate. That delegate is going to contain a reference to label1, an instance member of the Form. So is there a circular reference from the Timer to the Form?
I don't know the answer, I'm finding it a bit difficult to reason about. Because I don't know, I would remove the use of the lambda in Delayed, making it a proper method and having it, in addition to stopping the timer (which is the sender parameter of the method), also remove the event.
Usually lambdas do not cause problems for the garbage collection. In this case, the timer instance only exists locally and the reference in the lambda does not prevent the garbage collection to collect the instances (see also this question).
I actually tested this again using the .NET Memory Profiler. The timer objects were collected just fine, and no leaking happened. The profiler did give me a warning that there are instances that “[…] have been garbage collected without being properly disposed” though. Removing the event handler in itself (by keeping a reference to it) did not fix that though. Changing the captured timer reference to (Timer)s did not change that either.
What did help—obviously—was to call a timer.Dispose() in the event handler after stopping the timer, but I’d argue if that is actually necessary. I don’t think the profiler warning/note is that critical.
If all you're trying to do is change the text when the timer ticks, would you not be better off putting...
label1.Text = "second";
...In the timer tick, either before or after you change the timer to enabled = false;
Like so;
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
label1.Text = "second";
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
timer.Start();
}
private bool Delay(int millisecond)
{
Stopwatch sw = new Stopwatch();
sw.Start();
bool flag = false;
while (!flag)
{
if (sw.ElapsedMilliseconds > millisecond)
{
flag = true;
}
}
sw.Stop();
return true;
}
bool del = Delay(1000);

Stop loop in class from another class

So I have two event handlers button1_Click() and button2_Click()
In button1_Click() I have something running like this:
toGet = textbox1.Text;
got = 0;
while (got <= toGet)
{
//DoStuff
}
But button2_Click is supposed to be a stop button, and stop button1 early.
How do I go about this?
Thanks for the help. I saw this article here about it, but couldn't get it to work.
Windows.Forms answer
The least sophisticated method is this:
private bool m_stop;
private void button1_Click (object s, EventArgs ea)
{
try
{
// Don't forget to disable all controls except the ones you want a user to be able to click while your method executes.
toGet = textbox1.Text;
got = 0;
while (got <= toGet)
{
Application.DoEvents ();
// DoEvents lets other events fire. When they are done, resume.
if (m_stop)
break;
//DoStuff
}
finally
{
// Enable the controls you disabled before.
}
}
private void button2_Click (object s, EventArgs ea)
{
m_stop = true;
}
It has the distinct advantage of letting you execute button1_Click on the UI thread, still lets the UI respond to your stop button.
It has a disadvantage that you must protect against reentrancy. What happens if they click your button1 while button1_click is already executing!?!?
Edit: Another way I have used is to use a Timer instead of a loop. Then, the stop method just stops the timer.
As much as I understood, correct me if I'm wrong, you're on single thread.
Wired, but you can check for single boolean value inside the your While loop, just as post suggested.
May be to make life easier (may be this is what "couldn't get it to work" means) is inside loop call
1) Windows Forms: Application.DoEvents()
2) WPF (little bit more tricky) : DoEvents in WPF
This to make breathe system.
You need to start the process inside the button1 in new thread, and when you press the button2 flag a local variable to false to stop the loop. like:
using System.Threading;
private volatile bool _requestStop = false;
private readonly object _oneExecuteLocker = new object();
private void OnButton1Click(ojbect sender, EventArgs e)
{
new Thread(() =>
{
if (Monitor.TryEnter(_oneExecuteLocker))
{//if we are here that is means the code is not already running..
try
{
while (!_requestStop)
{
//DoStuff
}
}
finally
{
Monitor.Exit(_oneExecuteLocker);
}
}
}){ IsBackground = true }.Start();
}
private void OnButton2Click(object sender, EventArgs e)
{
_requestStop = true;
}
Notes:
When ever you want to update a UI control inside the newly created thread you should use contorl.Invoke(/*the code get/set or call method in the UI*/).
The Monitro.Enter is just to be sure that your code will not executed multiple time per click if it already running.

Task with Timer crashing a program

I've a little program, that parses all the log files created by another program, and locked by it ( so, no way I can edit or delete those files) . The program runs just fine, and I do it starting a new Task every 10 seconds:
System.Timers.Timer aTimer = new System.Timers.Timer();
public Form1()
{
InitializeComponent();
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 10000;
aTimer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
var t = Task<int>.Factory.StartNew(() => convert());
}
the only problem arises when there are too many log files : if a new Task is started before the end of the previous one, the program crashes.
So, any idea on how to solve this behaviour, or better solutions to the problem?
You could use the lock() statement to lock on an object variable. On the other hand, you might run into thread deadlocks if the parsing of the log files consistently takes longer than the timer interval.
In your OnTimedEvent() function, I would check a boolean member variable that skips the parsing if you are already performing a parse. For example:
public class MyTimerClass
{
private bool isParsing;
// Other methods here which initiate the log file parsing.
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (!isParsing)
{
isParsing = true;
ParseLogFiles();
isParsing = false;
}
}
}
The simple solution would be to wait until the previous task is completed.
Write an event that sends a callback when the file is done being parsed.
This is the best I can do with the code provided.
Have you tried to use lock statement inside OnTimeEvent?
http://msdn.microsoft.com/en-us/library/c5kehkcz(v=VS.100).aspx
You could create a static boolean variable called IsRunning and set it to true when you are moving the logs, before you start moving the logs just check if IsRunning is set to true.
private static bool IsRunning = false;
public void MoveLogs()
{
if (!IsRunning)
{
IsRunning = true;
//Copy log files
IsRunning = false;
}
}
In the current accepted answer there is still the possibility of a race condition in a multi-threaded situation. However unlikely in your case because of the interval, another more threading appropriate solution is to use Monitor.TryEnter
public class MyTimerClass
{
private object _syncObject = new object();
// Other methods here which initiate the log file parsing.
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
if (Monitor.TryEnter(_syncObject) )
{
try
{
ParseLogFiles();
}
finally
{
Monitor.Exit(_syncObject);
}
}
}
}
I believe this is cleaner and gets you in the habit of using the proper thread synchronization mechanism in the framework.

How do I call a function without the Main function in C sharp?

trying to run a function without putting it in the Main() when the program is run.
how do I start the new created function?
trying to call RunMix() in the Main() but get an error because of the lable1
namespace mixer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int i = 0;
public void RunMix()
{
while (i == 0)
{
label1.Text = knob1.Angle.ToString();
Application.DoEvents();
}
}
private void Form1_Load(object sender, EventArgs e)
{
RunMix();
}
}
}
In a console application, the Main() method is the entry point into the application. You have to put you code to start the application in there.
If you only want to test the function you can use the NUNIT or the Microsofts Unit Testing Framework. Otherwise you have to call the function from the Main().
Alright my first answer was completely off the topic because of your mysterious question. Now that you have updated it I have better - not complete - understanding of what do you mean.
Looking at code I guess what you are trying to do is to change the value of label when knob1 control's angle changes. If knob1 is a control it should have a change event and you should change value of label1 inside knob1_change event handler. If knob1 doesn't have any event - highly unlikely - then you should use a timer instead. Loop is simply a bad idea in your situation. Timer should work like this
Timer timer = new Timer();
public void RunMix(object sender, EventArgs e)
{
label1.Text = knob1.Angle.ToString();
}
private void Form1_Load(object sender, EventArgs e)
{
timer.Interval = 100;
timer.Tick += new EventHandler(RunMix);
timer.Start();
}
Stop timer when form is closed or use activate/deactivate cycle depending upon your requirement.
You can't have another method besides Main as an entry point for the app.
For ex you can't start a program from a function like this:
public static MyMain(string[] args)
{
}
This is a java code for the same but i don't know the same in C#.
But i think it can be possible in C# too.
class staticEx {
static
{
System.out.println("Inside Static
Block");
System.exit(0);
} }
The above code is tested and got it from here while GOOGLEing.
There can be a possibility of similar thing in C# as well.

Categories

Resources