It's clear: For example, imagine a button in my form. When a user clicks on the button, some void method should run after 30 seconds.
There would be a void method DoAfterDelay that takes two input parameter. The first one is the method to do (using delegates), and the other one is the time interval. So I'll have:
public delegate void IVoidDelegate();
static void DoAfterDelay(IVoidDelegate TheMethod, TimeSpan Interval)
{
// *** Some code that will pause the process for "Interval".
TheMethod();
}
So, I just need a piece of code to pause the process for a specific time interval. Heretofore, I used this code to do that:
System.Threading.Thread.Sleep(Interval);
But this code is no good for me, because it stops the whole process and freezes the program. I don't want the program to get stuck in the DoAfterDelay method. That's why the Thread.Sleep is useless.
So could anyone suggest a better way? Of course I've searched about that, but most of the solutions I've found were based on using a timer (like here for example). But using a timer is my last opinion, because the method should run once and using timers makes the program confusing to read. So I'm looking for a better solution if there is. Or maybe I have to use timers?
I guess I have to play with threads, but not sure. So I wonder if anyone could guide me to a solution. Thanks in advance.
Can you use a task?
Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(Interval);
TheMethod();
});
This is where you can use the async await functionality of .Net 4.5
You can use Task.Delay an give the delay in miliseconds.
This is a very clean way. ex:
private async void button1_Click(object sender, EventArgs e)
{
await Task.Delay(5000);
TheMethod();
}
There are several methods of creating thread but of course, it depends on what you are doing.
You can create a thread on the fly like this:
Thread aNewThread = new Thread(
() => OnGoingFunction()
);
aNewThread.Start();
This thread will be running in the background. The function you want to do should have a sleep method to sleep when its done processing. So something like this:
private void OnGoingFunction()
{
//Code....
Thread.Sleep(100); //100 ms, this is in the thead so it will not stop your winForm
//More code....
}
I hope that helps.
Another option is to create the thread whenever you need to process it and not worry about the sleep option. Just create a new thread every time to load the process
You should create a Coroutine
public IEnumerator waitAndRun()
{
// WAIT FOR 3 SEC
yield return new WaitForSeconds(3);
// RUN YOUR CODE HERE ...
}
And call it with:
StartCoroutine(waitAndRun());
DoAfterDelay starts a timer that just runs once, that when it expires it calls your void 'TheMethod'function.
Why would this be messy?
You can specify the exact seconds by using
DateTime runTime = new DateTime();
double waitSeconds = (runTime - DateTime.Now).TotalSeconds;
Task.Factory.StartNew(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(waitSeconds));
YourMethod();
});
runTime => When you want to execute the method.
Here's what you want:
public static void Example1c()
{
Action action = DoSomethingCool;
TimeSpan span = new TimeSpan(0, 0, 0, 5);
ThreadStart start = delegate { RunAfterTimespan(action, span); };
Thread t4 = new Thread(start);
t4.Start();
MessageBox.Show("Thread has been launched");
}
public static void RunAfterTimespan(Action action, TimeSpan span)
{
Thread.Sleep(span);
action();
}
private static void DoSomethingCool()
{
MessageBox.Show("I'm doing something cool");
}
One of the benefits of using Action is that it can be easily modified to pass in parameters. Say you want to be able to pass an integer to DoSomethingCool. Just modify thusly:
public static void Example1c()
{
Action<int> action = DoSomethingCool;
TimeSpan span = new TimeSpan(0, 0, 0, 5);
int number = 10;
ThreadStart start = delegate { RunAfterTimespan(action, span, number); };
Thread t4 = new Thread(start);
t4.Start();
MessageBox.Show("Thread has been launched");
}
public static void RunAfterTimespan(Action<int> action, TimeSpan span, int number)
{
Thread.Sleep(span);
action(number);
}
private static void DoSomethingCool(int number)
{
MessageBox.Show("I'm doing something cool");
}
Very flexible...
Here's a simple extension against Dispatcher that you can use in a non-blocking way.
public static void InvokeAfter(this Dispatcher dispatcher, int milliseconds, Action delayedAction) {
Task.Factory.StartNew(() => {
System.Threading.Thread.Sleep(milliseconds);
dispatcher.Invoke(delayedAction);
});
}
And here's how you use it with a Lambda:
SomeLabel.Dispatcher.InvokeAfter(3000, () => {
SomeLabel.Text = "Hello World";
});
You can also use it with anything that matches Action. Here's an example using a local function...
void doLater(){
SomeLabel.Text = "Hello World";
}
// Pass the action itself, not the result of the action (i.e. don't use parentheses with 'doLater'.)
SomeLabel.Dispatcher.InvokeAfter(3000, doLater);
Note: You can then call it against any dispatcher object where you would normally call Invoke. For safety, I like to invoke it using the dispatcher handling the control I'm updating.
Related
Qt has a neat functionality to do timed action with Lambda.
An action can be done after a delay with a single line of code:
QTimer::singleShot(10, [=](){
// do some stuff
});
Although I haven't found equivalent in C#.
The closest I got was
Timer timer = new Timer();
timer.Interval = 10;
timer.Elapsed += (tsender, args) => {
// do some stuff
timer.Stop();
};
timer.Start();
But it's far from (visually) clean.
Is there a better way to achieve this ?
The use case is sending data on a serial line to some hardware, upon a button click or action, it is often required to send a command, and a packet a few ms later.
Solution with a helper function:
public void DelayTask(int timeMs, Action lambda)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = timeMs;
timer.Elapsed += (tsender, args) => { lambda.Invoke(); };
timer.AutoReset = false;
timer.Start();
}
Called by
DelayTask(10, () => /* doSomeStuff...*/ );
The closest thing I would think of would be something like an helper function like you suggested:
public static class DelayedAction
{
public static Task RunAsync(TimeSpan delay, Action action)
{
return Task.Delay(delay).ContinueWith(t => action(), TaskScheduler.FromCurrentSynchronizationContext());
}
}
The usage of the class would be close to what you know with Qt:
await DelayedAction.RunAsync(TimeSpan.FromSeconds(10), () => /* do stuff */);
Update
As mentioned in an existing SO question, ContinueWith does not keep the synchronization context by default.
In the current question, the lambda is updating some UI control and, as such, must be run on the UI thread.
To do so, the scheduler must specify the synchronization context when calling the method ContinueWith (TaskScheduler.FromCurrentSynchronizationContext()) to make sure such update is possible.
You should use System.Threading.Timer instead of System.Timers.Timer. System.Timers.Timer is multithreaded timer meant to be used with desktop applications, which is why it inherits from Component and requires configuration through properties.
With a System.Threading.Timer though you can create a single-fire timer with a single constructor call :
var timer= new Timer(_=>lambda(),null,timeMS,Timeout.Infinite);
This quick & dirty console app:
static void Main(string[] args)
{
var timeMS = 1000;
var timer = new Timer(_ => Console.WriteLine("Peekaboo"), null, timeMS, Timeout.Infinite);
Console.ReadKey();
}
Will print Peekaboo after 1 second even though the main thread is blocked by ReadKey();
Using Microsoft's Reactive Framework (NuGet "System.Reactive") you can do this:
IDisposable subscription =
Observable
.Timer(TimeSpan.FromMilliseconds(10.0))
.Subscribe(_ => { /* Do Stuff Here */ });
The IDisposable let's you cancel the subscription before it fires by calling subscription.Dispose();.
I am working with one application(C# Service), where I need some functionalities like below
Main()
{
App.A();
App.B();
}
App
{
static A()
{
While(true)
{
// Thread logic comes here
Thread.Sleep(60000)
}
}
static B()
{
While(true)
{
// Thread logic comes here
Thread.Sleep(1000)
}
}
}
I need to execute 2 different thread logics in one class
Both is required with different sleep time
How to keep running both the functionalities in this case ? Suggest me any alternative to achieve the same.
Thanks in advance :-)
You either need a Threads / Tasks or use some sort of Timer. There are many ways to do this but you really need to understand what you want to do.
However these might give you food for thought
Disclaimer, You should research these approaches especially tasks, before you attempt this.
Option 1
Task.Run(async () =>
{
while (true)
{
// do the work in the loop
await Task.Delay(60000);
}
});
Option 2
DispatcherTimer _timer = new DispatcherTimer();
void DoWorkTimer()
{
_timer.Interval = TimeSpan.FromMilliseconds(200);
_timer.Tick += _timer_Tick;
_timer.IsEnabled = true;
}
void _timer_Tick(object sender, EventArgs e)
{
// do the work in the loop
}
I have a static method, which can be called from anywhere. During execution it will encounter Invoke. Obviously when this method is called from UI thread it will deadlock.
Here is a repro:
public static string Test(string text)
{
return Task.Run(() =>
{
App.Current.Dispatcher.Invoke(() => { } );
return text + text;
}).Result;
}
void Button_Click(object sender, RoutedEventArgs e) => Test();
I've read multiple questions and like 10 answers of #StephenCleary (even some blogs linked from those), yet I fail to understand how to achieve following:
have a static method, which is easy to call and obtain result from anywhere (e.g. UI event handlers, tasks);
this method should block the caller and after it the caller code should continue run in the same context;
this method shouldn't freeze UI.
The closest analogy to what Test() should behave like is MessageBox.Show().
Is it achieve-able?
P.S.: to keep question short I am not attaching my various async/await attempts as well as one working for UI calls, but terrible looking using DoEvents one.
You can not.
Even just 2 of those 3 requirements can't be achieved together - "this method should block the caller" is in conflict with "this method shouldn't freeze UI".
You have to make this method either asynchronous in some way (await, callback) or make it executable in small chunks to block UI only for short periods of time using for example timer to schedule each step.
Just to reiterate what you already know - you can't block thread and call it back at the same time as discusses in many questions like - await works but calling task.Result hangs/deadlocks.
To achieve something what MessageBox does (but without creating window) one can do something like this:
public class Data
{
public object Lock { get; } = new object();
public bool IsFinished { get; set; }
}
public static bool Test(string text)
{
var data = new Data();
Task.Run(() =>
{
Thread.Sleep(1000); // simulate work
App.Current.Dispatcher.Invoke(() => { });
lock (data.Lock)
{
data.IsFinished = true;
Monitor.Pulse(data.Lock); // wake up
}
});
if (App.Current.Dispatcher.CheckAccess())
while (!data.IsFinished)
DoEvents();
else
lock (data.Lock)
Monitor.Wait(data.Lock);
return false;
}
static void DoEvents() // for wpf
{
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Func<object, object>(o =>
{
((DispatcherFrame)o).Continue = false;
return null;
}), frame);
Dispatcher.PushFrame(frame);
}
The idea is simple: check if current thread need invoke (UI thread) and then either run DoEvents loop or block thread.
Test() can be called from UI thread or from another task.
It works (not fully tested though), but it's crappy. I hope this will make my requirements clear and I still need the answer to my question if there is any better "no, you can't do this" ;)
I wish my method to wait about 500 ms and then check if some flag has changed. How to complete this without blocking the rest of my application?
You can use await Task.Delay(500); without blocking the thread like Sleep does, and with a lot less code than a Timer.
Thread.Sleep(500) will force the current thread to wait 500ms. It works, but it's not what you want if your entire application is running on one thread.
In that case, you'll want to use a Timer, like so:
using System.Timers;
void Main()
{
Timer t = new Timer();
t.Interval = 500; // In milliseconds
t.AutoReset = false; // Stops it from repeating
t.Elapsed += new ElapsedEventHandler(TimerElapsed);
t.Start();
}
void TimerElapsed(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Hello, world!");
}
You can set AutoReset to true (or not set it at all) if you want the timer to repeat itself.
I don't really understand the question.
If you want to block before checking, use Thread.Sleep(500);
If you want to check asynchronously every x seconds, you can use a Timer to execute a handler every x milliseconds.
This will not block your current thread.
It the method in question is executing on a different thread than the rest of your application, then do the following:
Thread.Sleep(500);
System.Threading.Thread.Sleep(500);
Update
This won't block the rest of your application, just the thread that is running your method.
Using a timer should do the trick
if you need to use a thread then here is an example
void Main()
{
System.Threading.Thread check= new System.Threading.Thread(CheckMethod);
check.Start();
}
private void CheckMethod()
{
//Code
Thread.Sleep(500);
}
Asynchron Task:
var task = new Task (() => function_test()); task.Start();
public void function_test() { `Wait for 5000 miliseconds` Task.Delay(5000);` }
I've recently been struggling with the same issue where I needed an action to be run on schedule without blocking the UI.
Here's my solution:
private void Button_Click(object sender, RoutedEventArgs e)
{
RunOnSchedule(interval, cancellationToken);
}
private void RunOnSchedule(int interval, CancellationToken cancellationToken)
{
// Start the task you want to run on schedule
TaskToRunOnSchedule(args);
Task.Run(async () =>
{
// This loop checks if the task was requested to be cancelled every 1000 ms
for (int x = 0; x < interval; x+=1000)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
await Task.Delay(1000);
}
}).GetAwaiter().OnCompleted(() =>
{
// Once the task for delaying is completed, check once more if cancellation is requested, as you will reach this point regardless of if it was cancelled or not.
if (!cancellationToken.IsCancellationRequested)
{
// Run this method again
RunOnSchedule(interval, cancellationToken);
}
});
}
In a WinForms application, when I want to wait on the main thread without blocking the app, I usually use
private void Wait (double milliseconds)
{
DateTime next = System.DateTime.Now.AddMilliseconds(milliseconds);
while (next > System.DateTime.Now)
Application.DoEvents();
}
There are times in my application, when I need to invoke my timer manually.
I've tried the following:
int originalInterval = t.Interval;
t.Interval = 0;
t.Interval = originalInterval;
but it wasn't consistent.
I've created a new timer, inheriting from System.Timers.Timer, and exposed a "Tick" method - but the problem was that the "Elapsed" event then fired synchronously.
When I implemented the "Tick" with a new Thread - the results were, again, not consistent.
Is there a better way to implement it?
I once had the same problem, so I used the AutoResetEvent to know if the Elapsed was invoked successfully:
/// <summary>
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course)
/// </summary>
public class TickableTimer : System.Timers.Timer
{
public new event ElapsedEventHandler Elapsed;
private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true);
public TickableTimer()
: this(100)
{
}
public TickableTimer(double interval)
: base(interval)
{
base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed);
}
public void Tick()
{
new System.Threading.Thread(delegate(object sender)
{
Dictionary<string, object> args = new Dictionary<string, object>
{
{"signalTime", DateTime.Now},
};
TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args));
}).Start();
this.m_autoResetEvent.WaitOne();
}
void TickableTimer_Elapsed(object sender, ElapsedEventArgs e)
{
m_autoResetEvent.Set();
if (this.Elapsed != null)
this.Elapsed(sender, e);
}
}
It feels like you should look at your design a bit. Typically I try to avoid having the event handler method contain the actual work being done, but I rather try to let it be just a trigger, calling some other method that performs the work. That way you can invoke that other method from anywhere else as well:
private void Timer_Tick(object sender, EventArgs e)
{
new Thread(MethodThatDoesTheWork).Start();
}
private void MethodThatDoesTheWork()
{
// actual work goes here
}
Now, you can invoke MethodThatDoesTheWork from anywhere else within the class (either synchronously or asynchronously using a separate thread).
Alternatively, if MethodThatDoesTheWork should always be an asynchronous call, you can spawn the thread inside that method instead:
private void MethodThatDoesTheWork()
{
new Thread(() =>
{
// work code goes here
}).Start();
}
In these samples I have manually created threads. You can use that approach, the ThreadPool, Task or whatever other method of calling code asychronously, whichever fits best in your context.
Normally you shouldn’t need to fire a timer manually — you can always just run the event itself in a new thread. By and large, that’s basically what the timer does, and since you want to fire it manually, you don’t need the timer (for that manual invocation).
You didn’t specify any details as to what you mean by “not consistent”. The following should normally work:
Thread thread = new Thread(myDelegate);
thread.Start();
Of course, myDelegate can be a lambda in case you need to pass parameters:
Thread thread = new Thread(() => myMethod(param1, param2));
thread.Start();