Is there a way to write a safe one-second off-delay timer class in C# using exactly one System.Threading.Timer object?
Alternatively, what would be the simplest solution in general, assuming the input can get turned on and off a lot faster than once per second?
An off-delay timer could be described by this interface:
public interface IOffDelay
{
/// <summary>
/// May be set to any value from any thread.
/// </summary>
bool Input { get; set; }
/// <summary>
/// Whenever Input is true, Output is also true.
/// The Output is only false at startup
/// or after the Input has been continuously off for at least 1 second.
/// </summary>
bool Output { get; }
}
This is my first attempt:
public sealed class OffDelay : IOffDelay, IDisposable
{
public OffDelay()
{
timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
}
public void Dispose()
{
timer.Dispose();
}
public bool Input
{
get
{
lock (locker)
return _input;
}
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
if (_input == false)
timer.Change(1000, Timeout.Infinite);
else
{
_output = true;
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
}
private bool _input;
public bool Output
{
get
{
lock (locker)
return _output;
}
}
private bool _output;
private readonly Timer timer;
private readonly object locker = new object();
private void TimerCallback(object state)
{
lock (locker)
_output = false;
}
}
I can see that there is a race condition in this solution:
At the end of a one-second off period, the timer schedules the callback to run.
Someone quickly sets and resets the input, restarting the timer.
The callback now finally runs, checks the input and sets the output to false even though it should be true for another second.
Edit
Peter Duniho provided the correct answer, but it turns out I'm terrible at asking the right question. The OffDelay class should also do some operation when the output changes to false. Here is the modified code adapting Peter's basic principle:
public sealed class OffDelay : IOffDelay, IDisposable
{
public OffDelay()
{
timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
}
public void Dispose()
{
timer.Dispose();
}
public bool Input
{
get
{
lock (locker)
return _input;
}
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
if (_input == true)
_output = true;
else
{
stopwatch.Restart();
if (!timerRunning)
timer.Change(1000, Timeout.Infinite);
}
}
}
}
private bool _input;
public bool Output
{
get
{
lock (locker)
return _output;
}
}
private bool _output;
private readonly object locker = new object();
private readonly Timer timer;
private readonly Stopwatch stopwatch = new Stopwatch();
private bool timerRunning;
private void TimerCallback(object state)
{
lock (locker)
{
if (_input == true)
timerRunning = false;
else
{
var remainingTimeMs = 1000 - stopwatch.ElapsedMilliseconds;
if (remainingTimeMs > 0)
timer.Change(remainingTimeMs, Timeout.Infinite);
else
{
_output = false;
timerRunning = false;
DoSomething();
}
}
}
}
private void DoSomething()
{
// ...
}
}
Without a good Minimal, Complete, and Verifiable code example that clearly illustrates the question, including showing exactly what the context is and what constraints might exist, it's impossible to know for sure what answer would work for you.
But based on what you've included in your question, I would change your implementation so it doesn't rely on the timer:
public sealed class OffDelay : IOffDelay
{
public bool Input
{
get { lock (locker) return _input; }
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
_lastInput = DateTime.UtcNow;
}
}
}
private bool _input;
public bool Output
{
get { lock (locker) return (DateTime.UtcNOw - _lastInput).TotalSeconds < 1; }
}
private DateTime _lastInput;
}
Note that the above is susceptible to clock changes on the computer. If you have a need to work independently of the clock, you can replace DateTime.UtcNow with a Stopwatch instance, call Reset() on each change to the Input property, and use the Elapsed property of the Stopwatch to determine the length of time since last input.
Related
I'm not finding the bug, but this thread is stopping after some time of execution, it returns a message "Thread was being aborted."
Sometimes it takes a hour, in another takes four, I can't find a patern, in some cases it never stops, but I can't find anything relate to it
using System.Threading;
namespace NewMVC.infraestructure
{
public class Thread_iFood
{
private static bool inicializado = false;
static Thread_iFood instance = null;
static readonly object padlock = new object();
private const int timer = 30000;
static Timer thProcessaRet = new Timer(PollingIfood, null, Timeout.Infinite, Timeout.Infinite);
private Thread_iFood()
{
}
public static void Reiniciar()
{
inicializado = false;
instance = null;
}
public static Thread_iFood GetInstance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Thread_iFood();
}
}
}
return instance;
}
}
internal static async void PollingIfood(Object obj)
{
try
{
thProcessaRet.Change(Timeout.Infinite, Timeout.Infinite);
MetodosAuxiliares.BuscaPedidosIFood();
}
catch (Exception e)
{
LogErros.GravaLog(e, "Thread_iFood/PollingIfood");
//here is where is stopping (Thread was being aborted.)
}
finally
{
thProcessaRet.Change(timer, Timeout.Infinite);
}
}
public void Inicializa()
{
if (!inicializado)
{
inicializado = true;
thProcessaRet.Change(timer, timer);
}
}
}
}
I have this method:
public static async Task OpenPageAsync(string route)
{
await Shell.Current.GoToAsync(route, true);
}
If the method is called more than once in 5 seconds I would like the second call to be ignored. Has anyone come across a way to deal with this need?
Note that if it helps I do have access to create properities at the App level like this etc.
public partial class App : Application
{
public static int LastTapTime;
public static int TapTime;
In our project, we have created a 'MaxFrequencyUpdater' for exactly that cause.
Only difference: if within 5 seconds a new call comes in, it is delayed and executed after the 5 seconds interval.
namespace Utils
{
public class MaxFrequencyUpdater
{
private readonly WinformsExceptionHandler _exceptionHandler;
private readonly string _name;
private readonly int _millis;
private MethodInvoker _currentMethod;
private DateTime _lastExecuted = DateTime.MinValue;
private readonly object _updaterLockObject = new object();
public MaxFrequencyUpdater(string name, int maxFrequencyInMillis, WinformsExceptionHandler exceptionHandler)
{
_name = name;
_exceptionHandler = exceptionHandler;
_millis = maxFrequencyInMillis;
}
public void Update(MethodInvoker method)
{
lock (_updaterLockObject)
{
_currentMethod = method;
}
Task.Run(HandleWork);
}
private void HandleWork()
{
lock (_updaterLockObject)
{
// No longer bother, someone else handled it already
if (_currentMethod == null) return;
var now = DateTime.Now;
var delay = (int)(_millis - now.Subtract(_lastExecuted).TotalMilliseconds);
// Post-pone if too soon
if (delay > 0)
{
Task.Delay(delay).ContinueWith(HandleWork);
}
else
{
try
{
_currentMethod.Invoke();
}
catch (Exception e)
{
_exceptionHandler.HandleException(e);
}
_lastExecuted = now;
_currentMethod = null;
}
}
}
}
}
usage:
_maxFrequencyUpdater.Update(() =>
{
doSomething();
});
I'm using .NET 3.5 and need a slimmed version of a BlockingCollection (that doesn't necessarily need to be strong typed).
I've come up with the following which is more than enough for my needs in terms of features, but I think suffers from a race condition:
public class WuaBlockingCollection
{
private const int TimeoutInterval = 50;
private readonly Queue _queue = new Queue();
private readonly AutoResetEvent _event = new AutoResetEvent(false);
private readonly object _queueLock = new object();
public bool IsAddingComplete { get; private set; }
public void Add(object item)
{
lock (_queueLock)
{
if (IsAddingComplete)
throw new InvalidOperationException(
"The collection has been marked as complete with regards to additions.");
_queue.Enqueue(item);
}
_event.Set();
}
public object Take()
{
if (!TryTake(out var obj, Timeout.Infinite))
{
throw new InvalidOperationException(
"The collection argument is empty and has been marked as complete with regards to additions.");
}
return obj;
}
public bool TryTake(out object obj, int timeout)
{
var elapsed = 0;
var startTime = Environment.TickCount;
obj = null;
lock (_queueLock)
{
if (IsAddingComplete && _queue.Count == 0) return false;
}
do
{
var waitTime = timeout - elapsed;
if (waitTime > TimeoutInterval || timeout == Timeout.Infinite)
{
waitTime = TimeoutInterval;
}
if (_event.WaitOne(waitTime))
{
break;
}
} while (timeout == Timeout.Infinite || (elapsed = unchecked(Environment.TickCount - startTime)) < timeout);
if (timeout != Timeout.Infinite && elapsed >= timeout) return false;
var isQueueEmpty = false;
lock (_queueLock)
{
if (_queue.Count == 0)
{
return false;
}
obj = _queue.Dequeue();
if (_queue.Count > 0)
{
isQueueEmpty = true;
}
}
if (!isQueueEmpty)
{
_event.Set();
}
return true;
}
public void CompleteAdding()
{
lock (_queueLock)
{
IsAddingComplete = true;
}
_event.Set();
}
}
More specifically, in the TryTake() method around the if (!isQueueEmpty) part.
Basically in between isQueueEmpty being set and something being done with it's value another thread might do something that affects _queue.Count.
Theoretically only the Add() or CompleteAdding() should be able to do this (because multiple threads running TryTake() would be stuck at either the lock() or the _event.WaitOne()) but I'm not sure if this is either something to worry about nor how to actually fix it without putting the _event.Set() inside the lock itself which I believe might have adverse effects.
If the answer is to put the _event.Set() inside the lock, please clarify why this would not impact on the event and whether any further modifications are required.
This question already has answers here:
Use Unity API from another Thread or call a function in the main Thread
(5 answers)
Closed 6 years ago.
I'm having trouble with a UnityEngine version. (Can't upgrade, game is not mine)
The server RANDOMLY crashes when a specific UnityEngine method is used in a timer/thread (It was fixed in a version, I read It)
It happens totally random, I get a crash log, that starts from the timer/thread and ends at a UnityEngine method. (This never happens when I use It in the main thread)
My question is that Is It possible somehow to call the method from the main thread if the current thread != with the main thread?
Any help is appreciated
This Loom class is able to call the specific method from the Main thread, this is how you do It:
public class Loom : MonoBehaviour
{
public static int maxThreads = 10;
static int numThreads;
private static Loom _current;
private int _count;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
public void Awake()
{
_current = this;
initialized = true;
}
static bool initialized;
static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
var g = new GameObject("Loom");
_current = g.AddComponent<Loom>();
}
}
private List<Action> _actions = new List<Action>();
public struct DelayedQueueItem
{
public float time;
public Action action;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
public static void QueueOnMainThread(Action action)
{
QueueOnMainThread(action, 0f);
}
public static void QueueOnMainThread(Action action, float time)
{
if (time != 0)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
}
}
else
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
public static Thread RunAsync(Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return null;
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
public void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Use this for initialization
public void Start()
{
}
List<Action> _currentActions = new List<Action>();
// Update is called once per frame
public void Update()
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach (var a in _currentActions)
{
a();
}
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
foreach (var item in _currentDelayed)
_delayed.Remove(item);
}
foreach (var delayed in _currentDelayed)
{
delayed.action();
}
}
}
//Usage
public void Call()
{
if (Thread.CurrentThread.ManagedThreadId != TestClass.MainThread.ManagedThreadId)
{
Loom.QueueOnMainThread(() => {
Call();
});
return;
}
Console.WriteLine("Hello");
}
I've looked around and apparently I've got the choice between these libraries/ solutions:
One:
public void Awake() {
Invoke("InvokeAndPrint", 2);
}
void InvokeAndPrint() {
print("InvokeAndPrint 2");
}
Two:
void Start() {
StartCoroutine(WaitAndPrint(2.0F));
}
IEnumerator WaitAndPrint(float waitTime) {
yield return new WaitForSeconds(waitTime);
print("WaitAndPrint " + Time.time);
}
I want to know if there is any other better way?
This is a summary of my comments above
The only other method I can think of is old-school take note of the time at start; then in your Update() method check for elapsed time. You essentially do everything yourself. Though way more verbose than the above examples, it's type-safe and does not require any extra threads or thread job objects.
Simplest
First we need some fields defined:
private DateTime _start;
private bool _done;
In your start take note of the time:
void Start()
{
_start = DateTime.Now;
}
...then in your update check to see how much time has elapsed. If its greater than your timeout of say 2 seconds, fire off what-ever you wish to do - in this case print():
void Update()
{
if (! _done && (DateTime.Now - _start).TotalSeconds >= 2)
{
print("hello world");
_done = true;
}
}
That's it.
Re-usable Code
You'll probably find that there are many places where there is a need for this so wouldn't it be groovy if there was a way to cut down on repeated code. Perhaps a class to wrap it up in?
class DelayedJob
{
private readonly TimeSpan _delay;
private readonly Action _action;
private readonly DateTime _start;
public DelayedJob(TimeSpan delay, Action action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
_delay = delay;
_action = action;
_start = DateTime.Now;
}
/// <summary>
/// Updates this instance.
/// </summary>
/// <returns>true if there is more work to do, false otherwise</returns>
public bool Update()
{
if (DateTime.Now - _start >= _delay)
{
_action();
return false;
}
return true;
}
}
Then you could do something like this:
void Start()
{
_job = new DelayedJob(TimeSpan.FromSeconds(2), ()=> print("hello"));
}
...after updating your Update() accordingly:
void Update()
{
if (_job != null && !_job.Update())
{
_job = null;
}
}
Multiple Jobs
It's just a matter of placing them in a collection and processing it at runtime.
private List<DelayedJob> _jobs;
void Start()
{
_jobs = new List<DelayedJob>
{
new DelayedJob(TimeSpan.FromSeconds(2), () => print("star wars")),
new DelayedJob(TimeSpan.FromSeconds(3f), () => print("is coming!"))
};
}
...a few alterations to Update():
void Update()
{
bool again;
do
{
again = false;
// you probably want to optimise this so that we don't check the same items
// at the start again after removing an item
foreach (var delayedJob in _jobs)
{
if (!delayedJob.Update())
{
_jobs.Remove(delayedJob);
again = true; // start over
break;
}
}
}
while (again);
}