For a test I set up a class that simply counts up an int every second:
class TestComp1
{
public TestComp1()
{
var timer = new Timer(o => TestInt++,null,0,1000);
}
[ViewableProperty]
public int TestInt { get; set; } = 0;
}
The problem is that this Timer seems to stop working after roughly one minute.
If I rewrite it to use a Thread instead it keeps working. So it really seems to be the timer that stops.
Does anyone have an idea as to why this happens?
You have no reference to the timer outside of the scope of the constructor. The moment the constructor is finished the timer is no longer referenced and will be collected by the garbage collector.
You can fix it by using a field for the timer (or anything else that prevents not having a reference where you need the timer.)
class TestComp1
{
private Timer _timer;
public TestComp1()
{
_timer = new Timer(o => TestInt++,null,0,1000);
}
[ViewableProperty]
public int TestInt { get; set; } = 0;
}
Related
I have a class that creates a timer in the constructor.
The timer does exactly what I need it to do but I would also like to be able to use .Stop(); and .Start(); from the main program.
There is a lot more than this but this is enough to recreate my exact problem.
In the example below I have access to Monsters[index].M_timer but .Stop(); gives an error.
class Program
{
static void Main(string[] args)
{
int index = 0;
string name = "Spider";
monster[] Monsters = new monster[100];
Monsters[index] = Create_Monster(name);
/*
Monsters[1].M_timer.Stop(); <- not how I will be using this but I need the functionality here
*/
}
public static monster Create_Monster(string _name)
{
int timer = 0;
if (_name == "Spider")
{
timer = 4000;
}
monster build = new monster(false, timer);
return build;
}
}
class monster
{
public bool can_act;
public int _timer;
public object M_timer;
public monster(bool _can_act, int _timer)
{
can_act = _can_act;
Timer M_timer = new Timer();
M_timer.Interval = _timer;
M_timer.AutoReset = true;
M_timer.Enabled = true;
M_timer.Elapsed += TimerEvent;
}
public void TimerEvent(object source, ElapsedEventArgs e)
{
can_act = true;
}
}
An initial glance looks like you have a couple of issues. first, is scope. You have in your constructor a variable called M_timer which covers the class field M_timer. You are not acting upon the same objects here. You'd have to say something like this.M_timer = M_timer.
The second issue is that you'd have to cast the class field when you want to use it because it's a generic object. so you'd have to say something like ((Timer)Monsters[1].M_timer).Stop()
Damn, I should have given this just a few more minutes:
public object M_timer;
replaced with
public Timer M_timer;
I launch a timer with a callback function. But in this callback function I change/initialize a static object which is used after the launch of timer.
public class TimerExecute
{
// Assume that the "Dog" class exist with attribute Name initialized in the constructor
public static List<Dog> listDog = new List<Dog>();
public void callbackFunct(String param) {
// code...
listDog.Add(new Dog("Bob"));
// code...
}
public void Main() {
// add dogs Bob each 10sec
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
// return argumentoutofrange exception
Console.WriteLine(listDog[0].name);
}
}
When I use the static var, I have an Exception “argument out of range exception”. I think the problem is that callback function doesn’t finished her execution and the object is not yet initialize.
I tried this solution but this doesn't work :
// add dogs Bob each 10sec
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
WaitHandle h = new AutoResetEvent(false);
addbobs.Dispose(h);
Console.WriteLine(listDog[0].name);
But with this, it works :
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000);
Thread.Sleep(2000);
Console.WriteLine(listDog[0].name);
I want that my callback function finishes her execution before the next statement.
Do you have a solution for my problem ?
Last Edit : Yes I want to be able to pass parameters to callbackFunct
Here is what I came up with. The trick is to pass in the AutoResetEvent, and you have to call Set() on that event yourself which is what signals that the method is "completed" (really it just signals that the method was called whether the method is done or not). Because it appears you need other parameters sent to the call back in addition to the WaitHandle, I made a class to encapsulate both.
public void callbackFunct(object state)
{
var myParams = (CustomParametersWithWaitHandle)state;
string name = myParams.Parameter1;
AutoResetEvent wh = myParams.WaitHandle;
// code...
listDog.Add(new Dog(name));
// code...
wh.Set(); // signal that this callback is done
}
public void Main()
{
// add dogs Bob each 10sec
AutoResetEvent wh = new AutoResetEvent(false);
var myCustomParams = new CustomParametersWithWaitHandle(wh, "bob", 314);
Timer addbobs = new Timer(new TimerCallback(callbackFunct), myCustomParams, 0, 10000);
wh.WaitOne(); // blocks here until `Set()` is called on the AutoResetEvent
Console.WriteLine(listDog[0].name);
}
}
public class CustomParametersWithWaitHandle
{
public AutoResetEvent WaitHandle { get; set; }
public string Parameter1 { get; set; }
public int Parameter2 { get; set; }
public CustomParametersWithWaitHandle(AutoResetEvent h, string parameter1, int parameter2)
{
WaitHandle = h;
Parameter1 = parameter1;
Parameter2 = parameter2;
}
I'm quite sure you should be initializing your TimerCallback with new TimerCallback(callbackFunct) instead of only the name of the function. That should be the reason your list is not being filled with Bobs (I can't seem to understand how it even compiles but...). Like:
Timer addbobs = new Timer(new TimerCallback(callbackFunct), null, 0, 10000);
The your function shall look like this:
public void callbackFunct(object state){
//...
listDog.Add(new Dog("Bob"));
//...
}
It might be possible to initialize it without a new instance, but I'm not quite sure...
P.S.: I suspect that's not the code you're using, since it doesn't even compile. Take care to update it...
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I was struggling with implementation of a timer more than i should so i have decided to post a question here.
This is my class:
public static class CurrentPoint
{
public static Single X { get; set; }
public static Single Y { get; set; }
public static Single Z { get; set; }
public static long ID { get; set; }
public static float CalcVar { get; set; }
public static float CalcStatic { get; set; }
public static bool StartTimeOut()
{
return true;
}
}
I should have a method implemented in it StartTimeOut(). StartTimeOut() will be called from another class when some other method will execute.
In StartTimeOut() i should have a timer that would check if CalcVar will change in next 30 seconds.
Now if it will, i will receive a TRUE from my StartTimeOut() and timer should exit if not StartTimeOut() will return a false.
This check for CalcVar will be done under same CurrentPoint.ID. That means if ID changes durring timer checks timer should exit and StartTimeOut() would return a TRUE.
There should also be a check if timer is already running and again STOP timer if CalcVar reaches 0 under 30 seconds under same ID
and StartTimeOut() again returns TRUE.
I hope i haven't complicated this problem too much.
I created a small sample, do understand that whenever you call this function it will remain in the while loop as long as it is running. Perhaps you should call the StartTimeOut() function from inside another thread...
//do not forget
using System.Timers;
private Timer _timer;
private static long _id;
private static bool _returnValue;
private static int _achievedTime;
public static bool StartTimeOut()
{
//set your known values (you need to check these values over time
_id = ID;
_achievedTime = 0;
_returnValue = true;
//start your timer
Start();
while(_timer.Enabled)
{
//an empty while loop that will run as long as the timer is enabled == running
}
//as soon as it stops
return _returnValue;
}
//sets the timer values
private static void Start()
{
_timer = new Times(100); //describes your interval for every 100ms
_timer.Elapsed += HandleTimerElapsed;
_timer.AutoReset = true; //will reset the timer whenever the Elapsed event is called
//start your timer
_timer.Enabled = true; //Could also be _timer.Start();
}
//handle your timer event
//Checks all your values
private static void HandleTimerElapsed(object sender, ElapsedEventArgs e)
{
_achievedTime += _timer.Interval;
//the ID changed => return true and stop the timer
if(ID!= _id)
{
_returnValue = true;
_timer.enabled = false; //Could also be _timer.Stop();
}
if(CalcVar == 0) //calcVar value reached 0 => return false and stop the timer
{
_returnValue = false;
_timer.Enabled = false;
}
if(_achievedTime = 30000) //your 30s passed, stop the timer
_timer.Enabled = false;
}
this is what you call simply code do not test!
I have 2 different timers in my windows service each of which I am running at intervals of every 5 seconds, however they are both not being run at the same time.
My logs simplified logs look like the following
11:49:00 : Timer1
11:49:05 : Timer1
11:49:10 : Timer1
11:49:15 : Timer1
11:49:20 : Timer1
11:49:25 : Timer1
11:49:30 : Timer1
11:49:35 : Timer1
11:49:48 : Timer2
11:49:53 : Timer2
11:49:58 : Timer2
This continues with just one being activated for the correct period of 5 seconds then the other. I want both of them to be run.
I understand you will ask "why not put them in the same timer?" but i will be adding multiple more timers and the timing of these events are likely to change so I'd really like to fix this problem just now.
Here is my code,
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//Read or Create xml file to get necessary settings
SerializeIformBuilder();
//Checks for any user changes that may have occurred
var manageUsers = new App.BLL.ManageUsers();
System.Timers.Timer CreateNewUserTimer = new System.Timers.Timer();
System.Timers.Timer PasswordUpdateTimer = new System.Timers.Timer();
//Create Timer interval events
CreateNewUserTimer.Elapsed += new System.Timers.ElapsedEventHandler(manageUsers.TimedEvent_CreateNewUsers);
CreateNewUserTimer.Interval = 5000; //Once every 5 seconds
CreateNewUserTimer.Enabled = true;
PasswordUpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(manageUsers.TimedEvent_PasswordUpdate);
PasswordUpdateTimer.Interval = 5000; //Once every 5 seconds
PasswordUpdateTimer.Enabled = true;
}
The Interval of Timer is not actually guaranteed, same as you can't count on Thread.Sleep(5000) sleeping exactly 5 seconds.
If both delegates need to be executed at the exact same time, you'll need to implement your own special timer, e.g. one that holds multple delegates and knows their execution intervals.
simplified:
public class Job
{
public int ExecutionInterval { get; set; }
public Action Action { get; set; }
}
public class TimedExecutionHandler
{
private List<Job> jobs = new List<Job>();
public void Start()
{
// start internal thread on loop
}
public void Stop()
{
// interrupt thread
}
public void RegisterJob(Job job)
{
// store job
}
private void Loop()
{
int count = 0;
while (true)
{
Thread.Sleep(1000);
count++;
foreach (Job job in this.jobs)
{
if (count % job.ExecutionInterval == 0)
{
job.Action();
}
}
}
}
}
I have also had this issue, if your timers are running multiple things or doing complex calculations sometimes your program can run out of space, designated ram or overall just get too big(in terms of size and running lines of code). Just keep this in mind next time your using multiple timers or performing complicated tasks- your application had a designated amount of memory and timers use the memory up like crazy. Thanks! I hope that helped!
I have a powershell cmdlet written in C# (deriving from PSCmdlet) which will start a long-running task which should update its progress using WriteProgress() while it is running. Since powershell will not allow a separate thread to use WriteObject or WriteProgress I had to create a Queue<object> in the main thread and I add items to the queue from the task that I want to be written to the Pipeline/Progress. A while loop will dequeue objects as they come in and write to the pipline / progress bar.
This is working, but I wanted to see if there were any better practices for multi-threading with a powershell cmdlet that is written in C#/VB. For example with WPF I can always step onto the UI thread with UIComponent.Dispatcher.Invoke() if I need to update a progress bar or UI Component. Is there anything equivalent that I can use to 'step onto' the powershell thread to update the UI or write to the pipeline?
Here is an example of the queue system encapsulated in a class so it is easier to use and mimics Cmdllet.WriteObject's behavior. This way you can call WriteObject from within the separate thread and the object will be marshalled onto the powershell thread and written to the pipeline.
[Cmdlet("Test", "Adapter")]
public class TestCmdlet : PSCmdlet
{
protected override void ProcessRecord()
{
PowerShellAdapter adapter = new PowerShellAdapter(this, 100);
Task.Factory.StartNew(() => {
for (int x = 0; x < 100; x++) {
adapter.WriteObject(x);
Thread.Sleep(100);
}
adapter.Finished = true;
});
adapter.Listen();
}
}
public class PowerShellAdapter
{
private Cmdlet Cmdlet { get; set; }
private Queue<object> Queue { get; set; }
private object LockToken { get; set; }
public bool Finished { get; set; }
public int Total { get; set; }
public int Count { get; set; }
public PowerShellAdapter(Cmdlet cmdlet, int total)
{
this.Cmdlet = cmdlet;
this.LockToken = new object();
this.Queue = new Queue<object>();
this.Finished = false;
this.Total = total;
}
public void Listen()
{
ProgressRecord progress = new ProgressRecord(1, "Counting to 100", " ");
while (!Finished || Queue.Count > 0)
{
while (Queue.Count > 0)
{
progress.PercentComplete = ++Count*100 / Total;
progress.StatusDescription = Count + "/" + Total;
Cmdlet.WriteObject(Queue.Dequeue());
Cmdlet.WriteProgress(progress);
}
Thread.Sleep(100);
}
}
public void WriteObject(object obj)
{
lock (LockToken)
Queue.Enqueue(obj);
}
}
The answer provided by Despertar will work, but it can be improved on slightly.
Polling in a loop with Thread.Sleep should be replaced with use of an AutoResetEvent. This will cause the main thread to only "wake up" when there is actually data available, and can allow the cmdlet to complete faster than 100ms. The Thread.Sleep will always cause the cmdlet to take at least 100ms, even if it could run must faster. This might not be a problem if you have a simple cmdlet, but if you insert it into a complex pipeline this 100ms can easily multiply and cause things to run very slowly. Additionally, a lock should be taken when accessing the Queue on the main thread inside the Listen method.
The moral of the story: if you do cross-thread synchronization Thread.Sleep is not the right tool.
using System.Threading;
public class PowerShellAdapter
{
private Cmdlet Cmdlet { get; set; }
private Queue<object> Queue { get; set; }
AutoResetEvent sync;
private object LockToken { get; set; }
// volatile, since it will be written/read from different threads.
volatile bool finished;
public bool Finished
{
get { return finished; }
set
{
this.finished = value;
// allow the main thread to exit the outer loop.
sync.Set();
}
}
public int Total { get; set; }
public int Count { get; set; }
public PowerShellAdapter(Cmdlet cmdlet, int total)
{
this.Cmdlet = cmdlet;
this.LockToken = new object();
this.Queue = new Queue<object>();
this.finished = false;
this.Total = total;
this.sync = new AutoResetEvent(false);
}
public void Listen()
{
ProgressRecord progress = new ProgressRecord(1, "Counting to 100", " ");
while (!Finished)
{
while (true) { // loop until we drain the queue
object item;
lock (LockToken) {
if (Queue.Count == 0)
break; // exit while
item = Queue.Dequeue();
}
progress.PercentComplete = ++Count * 100 / Total;
progress.StatusDescription = Count + "/" + Total;
Cmdlet.WriteObject(item);
Cmdlet.WriteProgress(progress);
}
sync.WaitOne();// wait for more data to become available
}
}
public void WriteObject(object obj)
{
lock (LockToken)
{
Queue.Enqueue(obj);
}
sync.Set(); // alert that data is available
}
}
Note, I haven't actually tested this code, but it illustrates the idea.
You could take a look at the Start-Job cmdlet together with Get-Job, Wait-Job and Receive-Job.
Start-Job will effectively start a new thread and output a JobId which you can query with Receive-Job to get the output. You could then loop through all currently running jobs and update your progress bar.
Take a look at http://blogs.technet.com/b/heyscriptingguy/archive/2012/08/10/use-background-jobs-to-run-a-powershell-server-uptime-report.aspx