C# Self destroy object - c#

I have a form that operates independently (by itself; loads data, displays it for a few seconds and closes itself)
I have been calling it with new EventListPopup().Show();, and was counting on new Timer {Enabled = true, Interval = 5000}.Tick += (s,e) => {Close(); Dispose()} to self destroy the object.
If I set a break point on any line within the timer, I can see that it is not destroyed, and the timer repeats every 5 seconds (thus confirming that every time I display the popup, a new instance is added to a pool of already created instances)
Is there a valid confirmed way which allows me to self destroy the object? There is absolutely no way it would be used somewhere else (it is as temporary as it gets)
Thanks

You're Disposing the object itself, not the Timer. You don't have a reference to the Timer so your original code can't call Dispose on it. Disposing the object and not using it may eventually lead to the timer being garbage collected, but maybe not since event handlers can keep an object from being garbage collected.
The following code will manually disable the timer and then dispose it.
var timer = new Timer { Enabled = true, Interval = 5000 };
timer.Tick += (s, e) => { timer.Enabled = false; timer.Dispose(); Close(); Dispose(); }
Jeroen's comment is a better answer in that it's a better way to solve the original problem. You may need to use Dispatcher/BeginInvoke for the action to happen on the right thread.
Timers can be a good solution for a timer with a recurring interval or that have to be enabled/disabled regularly.

Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(_ => this.Invoke(new Action(() => Close()))); solved the problem.
Thanks to both!

Related

Stop creating new thread while system.timers.timer elapsed called

I am facing a issue when used to system.timers.time, i have a running process in my application.
with timer called my process start, but i want to use that process within the thread only.
because every time timer elapsed event called the new thread has been generated, but i want to prevent this and only using single thread in a process.
Here is my code.
Public void Watcher()
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 3000;
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
}
Public void OnTimedEvent
{
// process code here
}
Here, after every 3 seconds OnTimedEvent called and new thread created, but i don't want to create new thread every time.
So, how to prevent this, any idea?
If you have a UI you should simply use forms timer or dispatch timer. If you do not have a UI you can set the SynchronizationObject of the timer. This will be responsible for marshaling the execution to the right thread.
I would probably skip the synchronization object, and just do the marshaling in the event handler of the event.
In either case you will need some kind of message loop if you do not have a UI. This would have a threadsafe queue where the thread takes a message and process it, one at a time. For example, using a blocking collection of Action.
As mentioned by #MindSwipe in the comments. A new thread will not be generated per event. It will simply take threads from the threadpool. So the number of threads used should be fairly constant. The main reason for moving all execution to one thread is because it can make threadsafety easier to manage.

What is the expected behavior of a locally scoped Timer?

Specifically, if you create an instance of a Timer in the local scope, and then return from that scope:
1) Will the timer still execute?
2) When would it be garbage collected?
I offer these two scenarios:
Timer timer = new Timer(new TimerCallback((state) => { doSomething(); }));
timer.Change((int)TimeSpan.FromSeconds(30), (int)TimeSpan.FromSeconds(30));
return;
And
Timer timer = new Timer(new TimerCallback((state) => { doSomething(); }));
timer.Change((int)TimeSpan.FromSeconds(30), Timeout.Infinite);
return;
The TimerCallback has a reference to the method DoSomething(), and therefore (in your example) to this but there is no live reference going the other way so it should get collected...eventually
The timer might or might not execute, depends on whether garbage collection runs before the time executes. This is why it's good practice to keep a reference to the timer somewhere other than on the stack.
Note that this is not always problematic; for example, threads won't be collected as long as they are still running.
Here's a quick test:
class Program
{
static void Main(string[] args)
{
Something something = new Something();
Foo(something);
Console.ReadKey(true);
GC.Collect();
Console.ReadKey(true);
}
private static void Foo(Something something)
{
Timer timer = new Timer(new TimerCallback(something.DoIt),null,0,5);
return;
}
}
public class Something
{
public void DoIt(object state)
{
Console.WriteLine("foo{0}", DateTime.Now.Ticks);
}
}
This is essentially what the compiler blows it out to (the Lambda expression in your example). When you run this, you'll notice that as long as you don't hit the first key, it'll keep putting stuff out to the console. As soon as you hit a key, and the GC kicks in, it stops. Timer still has a reference to Something, but nothing has a reference to Timer, so it's gone.
If you're talking about System.Threading.Timer, it implements IDisposable, so you should maintain a reference to it so that you can call Dispose when you're no longer using it. I don't know the answer to your particular question, but you can investigate it in a console application by running many iterations and forcing GC.Collect() to see if the Timer continues to fire. My guess is that it will eventually be collected and stop firing, unless there is some statically rooted reference created internally.
On a side note, if you want a one-time Fire-and-forget timer, you can implement one by creating a state object with a reference to the Timer, so it can Dispose itself when the timer event fires. I have a TimerService class with a WhenElapsed(TimeSpan, Action) method that uses this pattern and it's very handy for creating timeouts without having to manage the Timer instance as a field in the containing class.

without adding timer or modify the form itself, can we show the form only for specific time span

Without modifying the form itself, can we make the from only show for some specific time, say 5 minutes.
You could do:
Thread.Sleep(...);
theForm.Invoke(...);
But at it's core, that's semantically equivalent to using a timer. The only difference is that the timer will pick a thread from the thread pool and in the "sleep" case you'd have to allocate the thread your self. I would advocate that's better to use the thread pool where you can, which means you should just use a timer.
FYI: You can use a timer without using a System.Windows.Forms.Timer control by using the System.Threading.Timer class. That would allow you to do what you want without having to modify the form.
There's no reason for the timer to have to be a member of the form. This will work just fine:
private void button1_Click(object sender, EventArgs e) {
var frm = new ThirdPartyForm();
var tmr = new Timer() { Interval = 5*60*1000, Enabled = true };
tmr.Tick += delegate { frm.Close(); tmr.Dispose(); };
frm.Show();
}
Yes you could (e.g., count to 5 minutes in a separate thread and close the form) but you would probably only be duplicating the functionality of a timer.
So, the form is 3rd party? Meaning, not in your program or what? If you must, you can simply close that form from another form or thread. If from another form, use a timer object there.

Why System.Timer doesn't change class member variable?

I have a while loop and in this loop, there is a if condition.
But condition will be changed by a timer. But timer never change global variable.
I cant understand.
Where is the problem?
Example:
bool enterHere = false;
Timer timer = new Timer(); //Timer Started
private void timer_Tick(object Sender, ...)
{
enterHere = true;
}
private void function()
{
while(...)
{
if(enterHere)
{
//Never enter here
}
}
}
As another lesson in why you should always post your real code when asking questions on SO...
It appears the solution to your problem is quite a bit simpler than the other answers suggest. The timer's Tick event is never going to be raised, thus the value of the enterHere variable is never going to be changed, because you never actually start the timer. More specifically, this line is incorrect:
Timer timer = new Timer(); //Timer Started
The constructor does not start the timer; you need to call its Start method. This is confirmed by the documentation, which says:
When a new timer is created, it is disabled; that is, Enabled is set to false. To enable the timer, call the Start method or set Enabled to true.
Absolutely no reason to muck about with things like Application.DoEvents if you don't have to.
I assume you're using a System.Windows.Forms.Timer in which case the Tick event will run on the same thread as your function(). You can put
Application.DoEvents();
Inside your loop to get the timer to tick. Alternatively you could use an other timer (such as the System.Threading one), which executes on a different thread.
What else are you doing in the WHILE(...) loop and have you checked the processor usage when your code is running? If the loop is running very quickly there is no time for your app to process it's messages and react to the timer message.
As deltreme says, inserting Application.DoEvents(); in the loop should give it a chance to process the message.
Ideally the timer should be running in a different thread if you have a loop like that. The timer will never be able to raise the event.
Alteratively you could call DoEvents() to allow the timer to do it's work

contextswitchdeadlock

Whilst debugging my program in VS 2008 I have come across the following error:
The CLR has been unable to transition from COM context 0x34fc1a0 to COM context 0x34fc258 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this
It appears to be deadlocking even though the code only contains a simple C# timer: See Snippet Below:
private void RequestWork()
{
// The timer will be re-intialised if there are still no wating jobs in the database
StopTimer();
// assign all the threads some work
InitialiseTimer();
}
/// <summary>
/// Initialise a timer with a timer interval configured from app.config. Enable the timer and
/// register an appropriate event handler
/// </summary>
private void InitialiseTimer()
{
if (m_Timer == null)
{
// look up the default backoff time from the config
string backOffInt = ConfigurationSettings.AppSettings["BackOffInterval"];
int backoffInterval = 1000;
m_Timer = new System.Timers.Timer();
// set the timer interval to 5 seconds
m_Timer.Interval = backoffInterval;
m_Timer.Elapsed += new ElapsedEventHandler(m_Timer_Elapsed);
}
m_Timer.Enabled = true;
}
private void StopTimer()
{
if (m_Timer != null)
{
m_Timer.Enabled = false;
}
}
void m_Timer_Elapsed(object p_Sender, ElapsedEventArgs p_E)
{
RequestWork();
}
As far as I know the timer should run, elapse and then initialise again, I can see no local reason for a deadlock.
I am aware of how to turn this error msg off but feel that this is not a solution, instead it is masking the problem.
You can turn this off if you think you've definitely not got a deadlock situation:
Debug->Exceptions->Managed Debug Assistants menu in Visual Studio and uncheck the ContextSwitchDeadlock
This is an infinite loop. You need to let your application pump some messages at least once every 60 seconds to prevent this exception to happen.
Try calling System.Threading.Thread.CurrentThread.Join(10) once in a while. There are other calls you can do that let the messages pump.
It seems that you are adding a new event handler each time you call InitialiseTimer. That way m_Timer_Elapsed will be called as many times as it has been added.
You should add the event handler just one time.
If your application hangs or not reponse even after you uncheck the box against contextswitchdeadlock. Put the following line before call of method or for loop.
In C#
System.Windows.Forms.Application.DoEvents();
and VB.NET / VB / ASP.NET
DoEvents()
Couple thoughts/questions:
1) The code snippet looks like your interval is every 1 second (not 5 as mentioned in the comments).
2) The big question is what is RequestWork() doing?
Without knowing what RequestWork() is doing, we can't really comment on why you are seeing a ContextSwitchDeadlock.
Somethings to think about with respect to this method
a) how long does it take?
b) is it accessing GUI elements?
Some MSDN comments on Elapsed:
If you use the Timer with a user
interface element, such as a form or
control, assign the form or control
that contains the Timer to the
SynchronizingObject property, so that
the event is marshaled to the user
interface thread.
-and-
The Elapsed event is raised on a
ThreadPool thread. If processing of
the Elapsed event lasts longer than
Interval, the event might be raised
again on another ThreadPool thread.
Thus, the event handler should be
reentrant.
I'm thinking since you have a 1 second timer, you might want to look into what happens in RequestWork and see how long its taking.

Categories