Expected all be executed on the main thread of .NET Core 2.0 console app, so the output being blocked for 10 seconds:
static void Main(string[] args)
{
WriteLine($"We are on {Thread.CurrentThread.ManagedThreadId}");
var subject = new Subject<long>();
var subscription = subject.Subscribe(
i => WriteLine($"tick on {Thread.CurrentThread.ManagedThreadId}"));
var timer = Observable.Interval(TimeSpan.FromSeconds(1))
.SubscribeOn(Scheduler.CurrentThread)
.Subscribe(i => subject.OnNext(i));
Thread.Sleep(10000);
}
Not the case though – a new line comes to console every other second being dispatched by random threads:
We are on 1
tick on 4
tick on 5
tick on 4
tick on 4
tick on 4
tick on 4
tick on 4
tick on 4
tick on 5
What did I do wrong?
The Scheduler.CurrentThread / CurrentThreadScheduler will queue items on the same thread that made call to schedule, which will be the thread that the timer happens to run on. Calling Scheduler.CurrentThread does not pin the execution of items scheduled via it to the thread that you make the call to Scheduler.CurrentThread on but rather the thread that calls .Schedule().
Also, you call SubscribeOn() which only affects the thread where the .Subscribe() call is going to be made. If you want to control the execution of the item processing, you rather want to call .ObserveOn().
If you want everything to run on the main thread, I suggest running the timer on the main thread, by specifying a scheduler on the interval observable:
Observable.Interval(TimeSpan.FromSeconds(1), Scheduler.CurrentThread)
Related
I am working in timer from System.Timers namespace in wpf application.I want some backend behaviour to execute with timers and call in n milliseconds.
Timer sampleTimer = new Timer();
sampleTimer.Elapsed += (sender, e) => CallElapsedEvent();
sampleTimer.Interval = 10000; //called every 10 seconds
sampleTimer.Enabled = true;
public void CallElapsedEvent(){
Console.WriteLine(DateTime.Now + " - CallElapsedEvent called");
}
Here is the output of the code
16:45:09 - CallElapsedEvent called
16:45:32 - CallElapsedEvent called
16:45:32 - CallElapsedEvent called
Expected behaviour is that after 9th second , it must fire again at 19.But it is called after an interval of 23 seconds and that too twice(at exactly the same sec).This is happening occassionally and causes some unexpected exception.Why is that happening so?
From what I read about ,it allocates thread pool thread every n interval seconds.If elapsed event is not finished it allocates some other new thread.So, in my case is there are no other free worker threads available at 19th second and waits for the thread.
Why is that happening so and is there any way to enter only one thread to fire at a time?
Presumptions/Prelude:
In previous questions, we note that Thread.Sleep blocks threads see: When to use Task.Delay, when to use Thread.Sleep?.
We also note that console apps have three threads: The main thread, the GC thread & the finalizer thread IIRC. All other threads are debugger threads.
We know that async does not spin up new threads, and it instead runs on the synchronization context, "uses time on the thread only when the method is active". https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/task-asynchronous-programming-model
Setup:
In a sample console app, we can see that neither the sibling nor the parent code are affected by a call to Thread.Sleep, at least until the await is called (unknown if further).
var sw = new Stopwatch();
sw.Start();
Console.WriteLine($"{sw.Elapsed}");
var asyncTests = new AsyncTests();
var go1 = asyncTests.WriteWithSleep();
var go2 = asyncTests.WriteWithoutSleep();
await go1;
await go2;
sw.Stop();
Console.WriteLine($"{sw.Elapsed}");
Stopwatch sw1 = new Stopwatch();
public async Task WriteWithSleep()
{
sw1.Start();
await Task.Delay(1000);
Console.WriteLine("Delayed 1 seconds");
Console.WriteLine($"{sw1.Elapsed}");
Thread.Sleep(9000);
Console.WriteLine("Delayed 10 seconds");
Console.WriteLine($"{sw1.Elapsed}");
sw1.Stop();
}
public async Task WriteWithoutSleep()
{
await Task.Delay(3000);
Console.WriteLine("Delayed 3 second.");
Console.WriteLine($"{sw1.Elapsed}");
await Task.Delay(6000);
Console.WriteLine("Delayed 9 seconds.");
Console.WriteLine($"{sw1.Elapsed}");
}
Question:
If the thread is blocked from execution during Thread.Sleep, how is it that it continues to process the parent and sibling? Some answer that it is background threads, but I see no evidence of multithreading background threads. What am I missing?
I see no evidence of multithreading background threads. What am I missing?
Possibly you are looking in the wrong place, or using the wrong tools. There's a handy property that might be of use to you, in the form of Thread.CurrentThread.ManagedThreadId. According to the docs,
A thread's ManagedThreadId property value serves to uniquely identify that thread within its process.
The value of the ManagedThreadId property does not vary over time
This means that all code running on the same thread will always see the same ManagedThreadId value. If you sprinkle some extra WriteLines into your code, you'll be able to see that your tasks may run on several different threads during their lifetimes. It is even entirely possible for some async applications to have all their tasks run on the same thread, though you probably won't see that behaviour in your code under normal circumstances.
Here's some example output from my machine, not guaranteed to be the same on yours, nor is it necessarily going to be the same output on successive runs of the same application.
00:00:00.0000030
* WriteWithSleep on thread 1 before await
* WriteWithoutSleep on thread 1 before first await
* WriteWithSleep on thread 4 after await
Delayed 1 seconds
00:00:01.0203244
* WriteWithoutSleep on thread 5 after first await
Delayed 3 second.
00:00:03.0310891
* WriteWithoutSleep on thread 6 after second await
Delayed 9 seconds.
00:00:09.0609263
Delayed 10 seconds
00:00:10.0257838
00:00:10.0898976
The business of running tasks on threads is handled by a TaskScheduler. You could write one that forces code to be single threaded, but that's not often a useful thing to do. The default scheduler uses a threadpool, and as such tasks can be run on a number of different threads.
The Task.Delay method is implemented basically like this (simplified¹):
public static Task Delay(int millisecondsDelay)
{
var tcs = new TaskCompletionSource();
_ = new Timer(_ => tcs.SetResult(), null, millisecondsDelay, -1);
return tcs.Task;
}
The Task is completed on the callback of a System.Threading.Timer component, and according to the documentation this callback is invoked on a ThreadPool thread:
The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.
So when you await the task returned by the Task.Delay method, the continuation after the await runs on the ThreadPool. The ThreadPool typically has more than one threads available immediately on demand, so it's not difficult to introduce concurrency and parallelism if you create 2 tasks at once, like you do in your example. The main thread of a console application is not equipped with a SynchronizationContext by default, so there is no mechanism in place to prevent the observed concurrency.
¹ For demonstration purposes only. The Timer reference is not stored anywhere, so it might be garbage collected before the callback is invoked, resulting in the Task never completing.
I am not accepting my own answer, I will accept someone else's answer because they helped me figure this out. First, in the context of my question, I was using async Main. It was very hard to choose between Theodor's & Rook's answer. However, Rook's answer provided me with one thing that helped me fish: Thread.CurrentThread.ManagedThreadId
These are the results of my running code:
1 00:00:00.0000767
Not Delayed.
1 00:00:00.2988809
Delayed 1 second.
4 00:00:01.3392148
Delayed 3 second.
5 00:00:03.3716776
Delayed 9 seconds.
5 00:00:09.3838139
Delayed 10 seconds
4 00:00:10.3411050
4 00:00:10.5313519
I notice that there are 3 threads here, The initial thread (1) provides for the first calling method and part of the WriteWithSleep() until Task.Delay is initialized and later awaited. At the point that Task.Delay is brought back into Thread 1, everything is run on Thread 4 instead of Thread 1 for the main and the remainder of WriteWithSleep.
WriteWithoutSleep uses its own Thread(5).
So my error was believing that there were only 3 threads. I believed the answer to this question: https://stackoverflow.com/questions/3476642/why-does-this-simple-net-console-app-have-so-many-threads#:~:text=You%20should%20only%20see%20three,see%20are%20debugger%2Drelated%20threads.
However, that question may not have been async, or may not have considered these additional worker threads from the threadpool.
Thank you all for your assistance in figuring out this question.
I have a dispatcher timer which has to act like a heartbeat every 500ms and write on a register on an anybus. I have set it with maximal priority:
m_HeartBeatTimer = new DispatcherTimer(DispatcherPriority.Render);
the problem is that when program is running sometimes the interval can enormously get longer up to 19 seconds:
[20/06/2017 17:00:01.182] HeartBeat 1 79
[20/06/2017 17:00:20.669] HeartBeat 0 80
of course there are other timers and other operations but shouldn't the timer be insensitive of those ones?
Is there any way to make it respect the correct timing?
thank you
.net has several types of timers. The Windows.Forms.Timer and DispatcherTimer both run on the UI thread. They only tick when the UI thread is not busy.. if the UI thread is locked into some task then the tick waits until the task is done.
If you want a true heartbeat then I recommend using System.Threading.Timer instead. This one will tick on a worker thread, so keep that in mind.
private System.Threading.Timer _timer;
private void go()
{
_timer = new Timer(_ => Timer_Tick(), null, 0, 1000 * 10); //every 10 seconds
}
private void Timer_Tick()
{
//this is not the main UI thread. Must invoke if you want to interact with the UI
}
I have a console server in C# that keeps running in a while(true) loop. But that takes > 50% CPU even if it is doing nothing. I tried Thread.Sleep it worked! Not eating my CPU anymore but, it do not resumes in the exact time specified and is not considered good practice. Am I doing the right thing? Or is there any other way than using while(true) and Thread.Sleep?
When you want to suspend thread for a while without consuming CPU resources, you usually use some WaitHandle (such as AutoResetEvent or ManualResetEvent) and call it's WaitOne() method to suspend thread until event that is supposed to wake it up occurs (e.g. key is pressed, new network connection arrives, asynchronous operation finishes, etc.).
To wake up thread periodically, you can use timer. I'm not aware of any timer in .NET Framework, that provides WaitHandle (of course you can easily create such class yourself), so have to use Timer and call AutoResetEvent.Set() manually on each tick in it's callback.
private static AutoResetEvent TimerWaitHandle = new AutoResetEvent(false);
static void Main()
{
// Initialize timer
var timerPeriod = TimeSpan.FromMilliseconds(500);
Timer timer = new Timer(TimerCallback, null, timerPeriod, timerPeriod);
while(true)
{
// Here perform your game logic
// Suspend main thread until next timer's tick
TimerWaitHandle.WaitOne();
// It is sometimes useful to wake up thread by more than event,
// for example when new user connects etc. WaitHandle.WaitAny()
// allows you to wake up thread by any event, whichever occurs first.
//WaitHandle.WaitAny(new[] { TimerWaitHandle, tcpListener.BeginAcceptSocket(...).AsyncWaitHandle });
}
}
static void TimerCallback(Object state)
{
// If possible, you can perform desired game logic here, but if you
// need to handle it on main thread, wake it using TimerWaitHandle.Set()
TimerWaitHandle.Set();
}
I can't comment, so i'll put it here.
Theorically with Thread.sleep(1) it won't use that much CPU.
You can get more info from this question/answer: What is the impact of Thread.Sleep(1) in C#?
You can use System.Threading.Timer class. It Provides a mechanism for executing a method on a thread pool thread at specified intervals.
Example
public void Start()
{
}
int dueTime = 1000;
int periodTS = 5000;
System.Threading.Timer myTimer = new System.Threading.Timer(new TimerCallback(Start), null, dueTime, periodTS);
This will call start method after 1 second from calling it and after that start will be called after every 5 second.
You can read more about Timer class here.
I have a program written in C# (Visual Studio), that works on a tray.
I want it to do one action every 10 minutes.
I have following code now:
while(true)
{
Thread.Sleep(10000);
// my stuff
}
But it doesn't work. It freezes a program.
You should use the timer object and not create a while loop.
System.Timers.Timer _timer = new System.Timers.Timer();
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
//30 seconds
_timer.Interval = 30000;
_timer.Start();
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//do your logic
}
Thread.Sleep makes the calling thead Sleep for an X ammount of time. If this thread is the frontend thread (the one responsible for handling messages), it will indeed freeze the application since any message for handling events or repainting wont be handeled untill the Thread wakes up again and gets a chance of handling the messages.
What you should do is schedule this logic every 10 seconds.
Drop a timer on your form and specify it to run each 10 seconds. Within the Tick event, call your custom action.
Thread.Sleep "stops" the current thread. if you only have one thread, everything is paused.
What do you want to achieve ?
Perhaps you need a second thread, or perhaps the better solution a timer which triggers a action every 10 minutes
s. Task.StartNew() or ThreadPool