I am trying to implement something that waits for a boolean to be true. If after 5 seconds the boolean is still not true then i will execute the error message code
This is what I am doing now. But this method just waits for 5 seconds for all cases, which is wasting time. How can I do something like that this that executes as soon as the variable becomes true?
Thread.Sleep(5000);
if (imageDisplayed == true) {
//success
}
else {
//failed
}
Better to use a ManualResetEvent for this.
// Somewhere instantiate this as an accessible variable to both
// display logic and waiting logic.
ManualResetEvent resetEvent = new ManualResetEvent(false);
// In your thread where you want to wait for max 5 secs
if(resetEvent.WaitOne(5000)) { // this will wait for max 5 secs before continuing.
// do your thing
} else {
// run your else logic.
}
// in your thread where you set a boolean to true
public void DisplayImage() {
// display image
display();
// Notify the threads waiting for this to happen
resetEvent.Set(); // This will release the wait/lock above, even when waiting.
}
Rule of thumb. Better not use sleeps in your production code unless you have a really, really, really good reason to do so.
You can set a timeout variable to the time that you want to stop waiting and use that, along with the check that you're waiting for, as a condition in a while loop. In the example below, we just sleep for a tenth of a second between checks, but you can adjust the sleep time (or remove it) as you see fit:
var timeout = DateTime.Now.AddSeconds(5);
while (!imageDisplayed && DateTime.Now < timeout)
{
Thread.Sleep(100);
}
// Here, either the imageDisplayed bool has been set to true, or we've waited 5 seconds
Break your sleeps up into "naps." ;)
for (int n = 0; n < 50; n++)
{
Thread.Sleep(100);
if (imageDisplayed)
{
// success
break;
}
}
//failed
Not quite instantly, but with a maximum 100ms latency.
Use a while loop and checking incrementally for your condition
var waitedSoFar = 0;
var imageDisplayed = CheckIfImageIsDisplayed(); //this function is where you check the condition
while(waitedSoFar < 5000)
{
imageDisplayed = CheckIfImageIsDisplayed();
if(imageDisplayed)
{
//success here
break;
}
waitedSoFar += 100;
Thread.Sleep(100);
}
if(!imageDisplayed)
{
//failed, do something here about that.
}
Sounds like you want to use the System.Timers.Timer class.
Setup your boolean variable to execute a function when it is set to true
System.Timers.Timer t;
private bool val;
public bool Val {
get { return val; }
set
{
if (value == true)
// run function here
val = value;
}
}
Then Setup your timers interval for every 5 seconds.
public Main()
{
InitializeComponent();
t = new System.Timers.Timer(5000);
t.Elapsed += T_Elapsed;
}
private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
throw new Exception();
}
To start the timer simply use t.Start() and t.Reset() to reset the timer
Related
I have a application where I'm checking if the signal read from a PLC is true or false, if its true - it does a set of calculations and if its false, it waits for the signal. I'm using a while loop to do this. But the problem is that the true state stays on for 1000ms, and the loop completes in less than 100ms, so it goes back up again and since the state is true it proesses it again. Hence for 1 signal that I receive from PLC, the loop runs for about 9-10 times. I tried adding thread.sleep but still it processes it more than once. I want the loop to run once when the state is true and then wait for it to get true again.
Here is the code:
bool isRunning = true;
private void WorkThreadFunction()
{
while (isRunning)
{
if (ethernetIPforSLCMicroCom1.Read("B3:254/1") == "True")
{
stopWatch = Stopwatch.StartNew();
int isTriggered;
Int32.TryParse(trigger, out isTriggered);
timer1.Start();
Thread.Sleep(10);
serialcheck();
System.GC.Collect();
}
}
I work on a program reading signal from GPIO pin and your problem is quite similar to mine, aka preventing a single on signal from being processed multiple times. My solution to this is I try to ensure that the signal is off first before I go to check whether the signal is on again.
while (isRunning)
{
var signal = ethernetIPforSLCMicroCom1.Read("B3:254/1");
if (signal == "True")
{
//do your stuff
}
while (signal == "True")
signal = ethernetIPforSLCMicroCom1.Read("B3:254/1");
}
The inner loop will wait for the signal to turn something other than "True" before it continues any other execution.
In order to wait for it to be true again you need to keep track of whether it has been false.
bool isRunning = true;
bool signalHasBeenFalse = true;
private void WorkThreadFunction()
{
while (isRunning)
{
if (ethernetIPforSLCMicroCom1.Read("B3:254/1") == "True" && hasBeenFalse )
{
signalHasBeenFalse = false;
stopWatch = Stopwatch.StartNew();
int isTriggered;
Int32.TryParse(trigger, out isTriggered);
timer1.Start();
Thread.Sleep(10);
serialcheck();
System.GC.Collect();
}
if ( ethernetIPforSLCMicroCom1.Read("B3:254/1") != "True" )
{
signalHasBeenFalse = true;
}
}
}
If I am reading it correctly you just need to put a break; in where your condition is met in the while loop.
I made an example here: https://dotnetfiddle.net/FsGryD
I would also add that you might consider if using SpinWait.SpinUntil(<boolean_condition>) might be a better option. (https://msdn.microsoft.com/en-us/library/system.threading.spinwait(v=vs.110).aspx).
I have used that previously on multi threading / IO waiting functions to wait for signals from devices.
I am quite new to C# and I have never used timers before.
I want to run a code in a while loop for 150 seconds. My idea is to set a timer before a while loop that will be turned off after 150 seconds. I have set a boolean exitFlag that is false by default and when the timer goes off it sets it to true.
public static System.Timers.Timer DL_stuckTimer;
static int secondleft = 150 ;
static bool exitFlag = false;
public static void SetTimer()
{
// Create a timer with a two second interval.
DL_stuckTimer = new System.Timers.Timer(2000); //tick every 2 second
// Hook up the Elapsed event for the timer.
DL_stuckTimer.Elapsed += DL_stuckTimerEvent;
DL_stuckTimer.AutoReset = true;
DL_stuckTimer.Enabled = true;
}
/*** Timer that goes off after 2.5 second and will tell the down
**/
public static void DL_stuckTimerEvent(Object myObject, EventArgs myEventArgs)
{
if (secondleft == 0)
{
DL_stuckTimer.Stop();
exitFlag = true;
}
secondleft -= 2;
}
SetTimer();
do{
//some code here
} while (!exitFlag);
This doesn't work . What am I doing wrong. It looks like the timer never goes on at all.
As Alessandro mentioned, you could use a Stopwatch instead:
public static void Main()
{
var sw = new Stopwatch();
sw.Start();
while(sw.ElapsedMilliseconds < 150000)
{
//Do stuff for 150 seconds.
Thread.Sleep(2000); //Wait 2 seconds before the next iteration/tick.
}
sw.Stop(); //150 seconds is over.
}
Let's start from the actual problem: it seems that you want to perform a long process which you want to terminate after 2 minutes if it hasn't been completed.
This is the kind of problem that can be solved with Tasks:
using System.Threading;
using System.Threading.Tasks;
...
// 2 minutes = 2 * 60 * 1000 milliseconds
using (CancellationTokenSource cts = new CancellationTokenSource(2 * 60 * 1000)) {
CancellationToken token = cts.Token;
try {
Task task = Task.Run(() => {
//TODO: put relevant code here
...
// Cancellation is a cooperative, that's why do not forget to check the token
token.ThrowIfCancellationRequested();
...
},
token);
await task;
}
catch (TaskCanceledException) {
// Task has been cancelled due to timeout
//TODO: put relevant code here
}
}
I would use a CancellationToken rather than a timer to do this.
Then you can create a CancellationTokenSource which will automatically cancel after a specified time.
Inside your loop, instead of checking an exit flag, you would check CancellationToken.IsCancellationRequested.
A full compilable console app example looks like this:
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(150));
Console.WriteLine("Started at time " + DateTime.Now);
SomeMethod(cancellationSource.Token);
Console.WriteLine("Finiehd at time " + DateTime.Now);
}
static void SomeMethod(CancellationToken cancellation)
{
do
{
Thread.Sleep(10); // Some code goes here.
}
while (!cancellation.IsCancellationRequested);
}
}
}
An advantage of doing it this way is that it is how Task-based cancellation works, and you can pass other kinds of cancellation tokens in if you want to cancel it another way.
You could also change your busy-loop so that it only did something every, say, 500ms, but will still exit the loop as quickly as possible when the cancellation token is signalled.
To do that you would use the CancellationToken.WaitOne() method as follows:
static void SomeMethod(CancellationToken cancellation)
{
do
{
// Do something every 500 ms.
}
while (!cancellation.WaitHandle.WaitOne(500)); // Wait up 500ms, but return immediatly if signalled.
}
I would like to run a function (funcA) and use another function (timerFunc) as a timer. If the running function (funcA) has run for 10 seconds, I would like to exit it using the timer function (timerFunc). Is this possible? Basically what I am trying to do:
void funcA() {
// check event 1
// check event 2
// check event 3
// time reaches max here! --exit--
//check event 4
}
If not, what is the best way to handle such scenarios? I have considered using a stop-watch but I'm not sure if that is the best thing to do, mainly because I do not know after what event the timeout will be reached.
Thread t = new Thread(LongProcess);
t.Start();
if (t.Join(10 * 1000) == false)
{
t.Abort();
}
//You are here in at most 10 seconds
void LongProcess()
{
try
{
Console.WriteLine("Start");
Thread.Sleep(60 * 1000);
Console.WriteLine("End");
}
catch (ThreadAbortException)
{
Console.WriteLine("Aborted");
}
}
You could put all of the events into an array of Action or other type of delegate, then loop over the list and exit at the appropriate time.
Alternately, run all of the events in a background thread or Task or some other threading mechanism, and abort/exit the thread when you get to the appropriate time. A hard abort is a bad choice, as it can cause leaks, or deadlocks, but you could check CancellationToken or something else at appropriate times.
I would create a list and then very quickyl:
class Program
{
static private bool stop = false;
static void Main(string[] args)
{
Timer tim = new Timer(10000);
tim.Elapsed += new ElapsedEventHandler(tim_Elapsed);
tim.Start();
int eventIndex = 0;
foreach(Event ev in EventList)
{
//Check ev
// see if the bool was set to true
if (stop)
break;
}
}
static void tim_Elapsed(object sender, ElapsedEventArgs e)
{
stop = true;
}
}
This should work for a simple scenario. If it's more complex, we might need more details.
I'm trying to invoke a method f() every t time, but if the previous invocation of f() has not finished yet, wait until it's finished.
I've read a bit about the available timers but couldn't find any good way of doing what I want, save for manually writing it all. Any help about how to achieve this will be appreciated, though I fear I might not be able to find a simple solution using timers.
To clarify, if t is one second, and f() runs the arbitrary durations I've written below, then:
Step Operation Time taken
1 wait 1s
2 f() 0.6s
3 wait 0.4s (because f already took 0.6 seconds)
4 f() 10s
5 wait 0s (we're late)
6 f() 0.3s
7 wait 0.7s (we can disregard the debt from step 4)
Notice that the nature of this timer is that f() will not need to be safe regarding re-entrance, and a thread pool of size 1 is enough here.
Use a System.Threading.Timer. Initialize it with a period of Timeout.Infinite so it acts like a one-shot timer. When f() completes, call its Change() method to recharge it again.
You could just use a 'global' level var (or more likely, a public property in the same class as f()) which returns true if f() is already running.
So if f() was in a class named TimedEvent, the first thing f() would do is set Running true
That way your timer fires every second, then launches the timed event if it isnt already running
if (!timedEvent.Running) timedEvent.f()
You commented that f() wouldnt repeat immediately if it took longer than the timer interval. Thats a fair point. I would probably include logic like that inside f() so that Running stays true. So it would look something like this:
public void f(int t) // t is interval in seconds
{
this.running = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
do
{
stopwatch.Reset();
// Do work here
} while (stopWatch.Elapsed.Seconds > t); // repeat if f() took longer than t
this.running = false;
}
You can use a non-restarting timer, then manually restart the timer after the method finishes.
Note that this will result in timing that is somewhat different from what you're asking for. (There will always be a gap of t time between invocations)
You could solve that by setting the interval to lastTick + t - Now, and running the method immediately if that's <= 0.
Beware of race conditions if you need to stop the timer.
You cannot get a timer to call you at exactly scheduled intervals. All timers do is call you back no sooner than the requested time.
Some timers are better than others (e.g. Windows.Forms.Timer is very erratic and unreliable compared to System.Threading.Timer)
To stop your timer being called re-entrantly, one approach is to Stop the timer while your method is running. (Depending on the type of timer you use, you either stop it and start it again when your handler exits, or with some timers you can request a single callback rather than repeating callbacks, so each execution of your handler simply enqueues the next call).
To keep the timing relatively even between these calls you can record the time since your handler last executed and use that to calculate the delay until the next event is required. e.g. If you want to be called once per second and your timer completed provcessing at 1.02s, then you can set up the next timer callback at a duration of 0.98s to accomodate the fact that you've already "used up" part of the next second during your processing.
A straightforward solution:
private class Worker : IDisposable
{
private readonly TimeSpan _interval;
private WorkerContext _workerContext;
private sealed class WorkerContext
{
private readonly ManualResetEvent _evExit;
private readonly Thread _thread;
private readonly TimeSpan _interval;
public WorkerContext(ParameterizedThreadStart threadProc, TimeSpan interval)
{
_evExit = new ManualResetEvent(false);
_thread = new Thread(threadProc);
_interval = interval;
}
public ManualResetEvent ExitEvent
{
get { return _evExit; }
}
public TimeSpan Interval
{
get { return _interval; }
}
public void Run()
{
_thread.Start(this);
}
public void Stop()
{
_evExit.Set();
}
public void StopAndWait()
{
_evExit.Set();
_thread.Join();
}
}
~Worker()
{
Stop();
}
public Worker(TimeSpan interval)
{
_interval = interval;
}
public TimeSpan Interval
{
get { return _interval; }
}
private void DoWork()
{
/* do your work here */
}
public void Start()
{
var context = new WorkerContext(WorkThreadProc, _interval);
if(Interlocked.CompareExchange<WorkerContext>(ref _workerContext, context, null) == null)
{
context.Run();
}
else
{
context.ExitEvent.Close();
throw new InvalidOperationException("Working alredy.");
}
}
public void Stop()
{
var context = Interlocked.Exchange<WorkerContext>(ref _workerContext, null);
if(context != null)
{
context.Stop();
}
}
private void WorkThreadProc(object p)
{
var context = (WorkerContext)p;
// you can use whatever time-measurement mechanism you want
var sw = new System.Diagnostics.Stopwatch();
int sleep = (int)context.Interval.TotalMilliseconds;
while(true)
{
if(context.ExitEvent.WaitOne(sleep)) break;
sw.Reset();
sw.Start();
DoWork();
sw.Stop();
var time = sw.Elapsed;
if(time < _interval)
sleep = (int)(_interval - time).TotalMilliseconds;
else
sleep = 0;
}
context.ExitEvent.Close();
}
public void Dispose()
{
Stop();
GC.SuppressFinalize(this);
}
}
How about using delegates to method f(), queuing them to a stack, and popping the stack as each delegate completes? You still need the timer, of course.
A simple thread is the easiest way to achieve this. Your still not going to be certain that your called 'precisely' when you want, but it should be close.... Also you can decide if you want to skip calls that should happen or attempt to catch back up... Here is simple helper routine for creating the thread.
public static Thread StartTimer(TimeSpan interval, Func<bool> operation)
{
Thread t = new Thread(new ThreadStart(
delegate()
{
DateTime when = DateTime.Now;
TimeSpan wait = interval;
while (true)
{
Thread.Sleep(wait);
if (!operation())
return;
DateTime dt = DateTime.Now;
when += interval;
while (when < dt)
when += interval;
wait = when - dt;
}
}
));
t.IsBackground = true;
t.Start();
return t;
}
For the benefit of people who land here searching for "re-entrancy": (I know this may be too late for the original question)
If one is not averse to using open source libraries that already provide for such functionality, I have successfully achieved this through an implementation using Quartz.NET
When you create a job and attach a trigger, you can specify what should be done if a previous trigger has not completed executing it's job
I'm writing a Windows service that runs a variable length activity at intervals (a database scan and update). I need this task to run frequently, but the code to handle isn't safe to run multiple times concurrently.
How can I most simply set up a timer to run the task every 30 seconds while never overlapping executions? (I'm assuming System.Threading.Timer is the correct timer for this job, but could be mistaken).
You could do it with a Timer, but you would need to have some form of locking on your database scan and update. A simple lock to synchronize may be enough to prevent multiple runs from occurring.
That being said, it might be better to start a timer AFTER your operation is complete, and just use it one time, then stop it. Restart it after your next operation. This would give you 30 seconds (or N seconds) between events, with no chance of overlaps, and no locking.
Example :
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((g) =>
{
Console.WriteLine(1); //do whatever
timer.Change(5000, Timeout.Infinite);
}, null, 0, Timeout.Infinite);
Work immediately .....Finish...wait 5 sec....Work immediately .....Finish...wait 5 sec....
I'd use Monitor.TryEnter in your elapsed code:
if (Monitor.TryEnter(lockobj))
{
try
{
// we got the lock, do your work
}
finally
{
Monitor.Exit(lockobj);
}
}
else
{
// another elapsed has the lock
}
I prefer System.Threading.Timer for things like this, because I don't have to go through the event handling mechanism:
Timer UpdateTimer = new Timer(UpdateCallback, null, 30000, 30000);
object updateLock = new object();
void UpdateCallback(object state)
{
if (Monitor.TryEnter(updateLock))
{
try
{
// do stuff here
}
finally
{
Monitor.Exit(updateLock);
}
}
else
{
// previous timer tick took too long.
// so do nothing this time through.
}
}
You can eliminate the need for the lock by making the timer a one-shot and re-starting it after every update:
// Initialize timer as a one-shot
Timer UpdateTimer = new Timer(UpdateCallback, null, 30000, Timeout.Infinite);
void UpdateCallback(object state)
{
// do stuff here
// re-enable the timer
UpdateTimer.Change(30000, Timeout.Infinite);
}
instead of locking (which could cause all of your timed scans to wait and eventually stack up). You could start the scan/update in a thread and then just do a check to see if the thread is still alive.
Thread updateDBThread = new Thread(MyUpdateMethod);
...
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if(!updateDBThread.IsAlive)
updateDBThread.Start();
}
Starting from .NET 6 there is a new timer available, the PeriodicTimer. This is a lightweight async-enabled timer, that becomes the perfect tool when overlapping executions should be strictly forbidden. You use this timer by writing an asynchronous method with a loop, and invoking it to start the loop:
private Task _operation;
private CancellationTokenSource _operationCancellation = new();
//...
_operation = StartTimer();
//...
private async Task StartTimer()
{
PeriodicTimer timer = new(TimeSpan.FromSeconds(30));
while (true)
{
await timer.WaitForNextTickAsync(_operationCancellation.Token);
try
{
DoSomething();
}
catch (Exception ex)
{
_logger.LogError(ex);
}
}
}
Instead of using a CancellationTokenSource, you can also stop the loop by disposing the PeriodicTimer. In this case the await timer.WaitForNextTickAsync() will return false.
It is possible that the DoSomething will be invoked subsequently with smaller interval than 30 seconds, but it's impossible that it will be invoked in overlapping fashion, unless you start accidentally two asynchronous loops.
This timer does not support disabling and reenabling it. If you need this functionality you could look at the third-party Nito.AsyncEx.PauseTokenSource component.
In case you are targeting a .NET version earlier than .NET 6, you could look at this question for an alternative: Run async method regularly with specified interval.
You could use the AutoResetEvent as follows:
// Somewhere else in the code
using System;
using System.Threading;
// In the class or whever appropriate
static AutoResetEvent autoEvent = new AutoResetEvent(false);
void MyWorkerThread()
{
while(1)
{
// Wait for work method to signal.
if(autoEvent.WaitOne(30000, false))
{
// Signalled time to quit
return;
}
else
{
// grab a lock
// do the work
// Whatever...
}
}
}
A slightly "smarter" solution is as follow in pseudo-code:
using System;
using System.Diagnostics;
using System.Threading;
// In the class or whever appropriate
static AutoResetEvent autoEvent = new AutoResetEvent(false);
void MyWorkerThread()
{
Stopwatch stopWatch = new Stopwatch();
TimeSpan Second30 = new TimeSpan(0,0,30);
TimeSpan SecondsZero = new TimeSpan(0);
TimeSpan waitTime = Second30 - SecondsZero;
TimeSpan interval;
while(1)
{
// Wait for work method to signal.
if(autoEvent.WaitOne(waitTime, false))
{
// Signalled time to quit
return;
}
else
{
stopWatch.Start();
// grab a lock
// do the work
// Whatever...
stopwatch.stop();
interval = stopwatch.Elapsed;
if (interval < Seconds30)
{
waitTime = Seconds30 - interval;
}
else
{
waitTime = SecondsZero;
}
}
}
}
Either of these has the advantage that you can shutdown the thread, just by signaling the event.
Edit
I should add, that this code makes the assumption that you only have one of these MyWorkerThreads() running, otherwise they would run concurrently.
I've used a mutex when I've wanted single execution:
private void OnMsgTimer(object sender, ElapsedEventArgs args)
{
// mutex creates a single instance in this application
bool wasMutexCreatedNew = false;
using(Mutex onlyOne = new Mutex(true, GetMutexName(), out wasMutexCreatedNew))
{
if (wasMutexCreatedNew)
{
try
{
//<your code here>
}
finally
{
onlyOne.ReleaseMutex();
}
}
}
}
Sorry I'm so late...You will need to provide the mutex name as part of the GetMutexName() method call.