I'm trying to start up a thread, storing it as a reference and then terminate it on a button click. But after starting the thread and having it execute some work, the reference has false in "IsAlive" and looking at the Thread.CurrentThread doesn't give me the same as i stored on execution.
Why can't i start a thread and later abort it from the same reference as i started it from?
Thread thread = new Thread(start);
thread.Start();
Thread thread = new Thread(start);
thread.Start();
void start (){`
await something();
No longer same thread
Could somebody explain why this is happening?
Thanks in advance!
In my start method i'm simply awaiting a list of tasks. I'm assuming these are executed by the thread i started the start method from, right?
Wrong.
When an await happens on an incomplete awaitable (typically: Task / Task<T> or ValueTask<T>), it registers a continuation and returns. If you return to the top of the call stack: your thread completes.
Separately, when the awaitable completes, the continuation will be invoked. This could be synchronously on the thread that is doing the completion, or it could be via a scheduler such as the sync-context.
The one thing it can't run on is the thread that did the await: because that thread has already finished.
Related
Lets assume I have the following simple program which uses the await operator in both DownloadDocsMainPageAsync() and Main(). While I understand that the current awaitable method gets suspended and continue from that point after the results are available, I need some clarity on the following points .
a) If the execution from Main() starts on Thread A from the threadpool , as soon as it encounters the await operator will this thread be returned to the threadpool for executing other operations in the program , for eg: if its a web app then for invocation of some Controller methods after button clicks from UI?
b) Will the await operator always take the execution on a new thread from the threadpool or in this case assuming there is no other method to be executed apart from Main() ,will it continue execution on the same thread itself (ThreadA)? If my understanding is correct who decides this , is it Garbage collector of CLR?
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class AwaitOperator
{
public static async Task Main()
{
Task<int> downloading = DownloadDocsMainPageAsync();
Console.WriteLine($"{nameof(Main)}: Launched downloading.");
int bytesLoaded = await downloading;
Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
}
private static async Task<int> DownloadDocsMainPageAsync()
{
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");
var client = new HttpClient();
byte[] content = await client.GetByteArrayAsync("https://learn.microsoft.com/en-us/");
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
return content.Length;
}
}
Actually, async/await is not about threads (almost), but just about control flow control. So, in your code execution goes in a Main thread (which is not from a thread pool, by the way) until reaches await client.GetByteArrayAsync. Here the real low-level downloading is internally offloaded to the OS level and the program just waits the downloading result. And still no additional thread are spawned. But, when downloading finished, the .NET runtime want to continue execution after await. And here it can see no SynchronizationContext (as a console application does not has it) and then runtime executes the code after await in any thread available in thread pool. So, the rest of code after downloading will be executed in the thread from the pool.
If you will add a SynchronizationContext (or just move the code in WinForms app where the context exists out-of-the-box) you will see that all code will be executed in the main thread on no threads will be spawned/taken in from the thread pool as the runtime will see SynchronizationContext and will schedule after-await code on the original thread.
So, the answers
a) Main starts on the Main thread, not on the thread pool's thread. await itself does not actually spawn any threads. On the await, if the current thread was from thread pool, this thread will be put back in thread pool and will be available for future work. There is an exception, when the await will continue immediately and synchronously (see below).
b) runtime decides on which thread execution will be continued after 'await' depending of the current SynchronizationContext, ConfigureAwait settings and the availability of the operation result on the moment of reaching await.
In particular
if SynchronizationContext present and ConfigureAwait is set to true (or omitted), then code always continue in the current thread.
if SynchronizationContext does not present or ConfigureAwait is set to false, code will continue in any available thread (main thread or thread pool)
if you write something like
var task = DoSomeWorkAsync();
//some synchronous work which takes a while
await task;
then you can have a situation, when task is already finished on the moment when the code reaches await. In this case runtime can continue execution after await synchronously in the same thread. But this case is implementation-specific, as I know.
additionally, this is a special class TaskCompletionSource<TResult> (docs here) which provides explicit control over the task state and, in particular, may switch execution on any thread selected by the code owning TaskCompletionSource instance (see sample in #TheodorZoulias comment or here).
Given the pre-condition that we are on the UI thread, is
// doing other stuff
await Task.Run(Long_IO_Bound_Operation);
// do more stuff
exactly the same as:
// doing other stuff
Long_IO_Bound_Operation();
// do more stuff
By "exactly the same" i mean that the end result, including freezing (or not) of the UI are the same?
note: pls refer to https://msdn.microsoft.com/en-us/library/hh156528.aspx before answering
Task.Run will spawn a new thread and execute the Long_IO_Bound_Operation on that thread freeing up the UI thread for something else. await keyword will guarantee the execution comes back to UI thread once task that was created by Task.Run completes.
In another words, if you were to not await the TaskRun, // do more stuff would execute right after Task.Run statement. But await keyword makes sure, // do more stuff is delayed until Long_IO_Bound_Operation completes on the thread that was spawned by Task.Run
await Task.Run(SomeProcess);
DoMoreStuff();
is the same as:
Task.Run(SomeProcess).ContinueWith(t=>DoMoreStuff(), TaskScheduler.FromCurrentSynchronizationContext());
So no, it's not "exactly the same" in that the first won't block the UI thread whereas the second would.
No. Only in the sense that while Long_IO_Bound_Operation() is being awaited the UI thread will not completely lock up and have the app display "Not Responding". Exectuion will not continue until Long_IO_Bound_Operation() completes, but it won't lock the UI thread.
i am building a WPF app where it needs job1 runs in the background; when job1 ends, it switches back to the UI thread using Task.ContinueWith and makes changes to the UI according to job1's result (in my case, starts another popup) and starts job2 in the background.
The problem is that, while job1 runs in a separate thread as it should, job2 runs in the UI thread (it blocks popup2). Maybe because job2 is started inside the ContinueWith block of task1? But why? It worked the first time, why not second time? How to fix this problem?
Thanks in advance!
enterPop(PopupTypes.popup1);
var task1 = new Task(() => job1()); //task runs in another thread
task1.ContinueWith(previousTask =>
{
//**back in UI thread**
//check result of job 1, start another popup in UI
exitPopup();
enterPop(PopupTypes.popup2);
//**SUPPOSEDLY** starts another background thread for task 2
var task2 = new Task(()=> job2());
task2.ContinueWith(previousTask =>{
//do task in UI thread...
},TaskScheduler.FromCurrentSynchronizationContext());
task2.Start();
}, TaskScheduler.FromCurrentSynchronizationContext());
task.Start();
It's not clear to me what the enterPop() and exitPopup() methods are supposed to do, as the code example is missing that detail. Maybe they are displaying some kind of window in the GUI? It's also not clear what code exists in the "check result of job 1" part, "do task in UI thread", etc.
Without these details, it's impossible to know what your code is actually doing.
In any case, Hans's advice is correct. It's not really clear from the incomplete code example why you get the behavior you're seeing (for that matter, it's not really entirely clear to me what behavior you're seeing). But it's likely that if you'd written the code in the more usual async/await pattern, it would work fine:
enterPop(PopupTypes.popup1);
await Task.Run(() => job1()); //task runs in another thread
//**back in UI thread**
//check result of job 1, start another popup in UI
exitPopup();
enterPop(PopupTypes.popup2);
// starts another background thread for task 2
await Task.Run(()=> job2());
exitPopup();
//do task in UI thread...
For bonus points, have the job1() and job2() methods return the result that you check (per the commend in your code), and use something like var result = await Task.Run(() => job1()); to retrieve the value (instead of whatever mechanism you're using now).
In some cases TaskScheduler may decide to execute Task in the current thread, e.g. read the following example from Jeffrey Richter's book CLR via c#:
When a thread calls the Wait method, the system checks if
the Task that the thread is waiting for has started executing. If it
has, then the thread calling Wait will block until the Task has
completed running. But if the Task has not started executing yet, then
the system may (depending on the TaskScheduler) execute the Task using
the thread that called Wait. If this happens, then the thread calling
Wait does not block; it executes the Task and returns immediately
I believe something similar happens in your logic. TaskScheduler just follows your task queue and decides to execute it syncronously. The easiest way out is to start task2 in default scheduler
task2.Start(TaskScheduler.Default);
i have main thread (MainThread) on which I create new thred (lets call it NewThread). In NewThread I call a method that want to invoke some method for MainThread.
The problem is that when I call NewThread.Join() from MainThread, Invoke method from NewThread cant be accomplished/terminate (and whole application freeze for ever...) because MainThread is waiting for NewThread to terminate...
sth like vicious circle... Any ideas how to solve it? I need to have possibility to terminate/abort NewThread from MainThread and be shure NewThread no longer exist.
I hope I was specific enough.
Main thread:
void method()
{
if(currentthread!=null)
{
currentthread.Join();
currentthread=null;
}
sth...
Backgroundworker worker = new Backgroundworker();
worker.DoWork += delegate (...)
{
currentthread=Thread.CurrentThread;
Func();
}
....
}
NewThread:
delegate void FuncDel();
void Func()
{
if(MainThread.InvokeRequired)
{
FuncDel funcD = new FuncDel();
MainThread.InvokeRequired(funcD);
return;
}
....
}
Well, the obvious answer is that your main thread should never Join() your worker thread if there's a chance the worker thread is going to try to Invoke() something on the main thread.
If you are only using Join() to wait for a shutdown on the main thread, you should first do something like a Thread.Abort(), or better yet, use a thread synchronization object like a Mutex or a shared variable, to indicate to the worker thread that it needs to abort. Once you have signaled the worker thread to abort, then allow your main thread to Join() it; your worker thread should always check to see if it has been aborted before trying to Invoke a method on the main thread.
If you're using Join() for some other reason, you should again look into the thread synchronization objects like a Mutex. These allow your threads to wait for each other to send them signals -- your worker thread could "wake up" your main thread before it needs to Invoke(), to ensure your main thread is getting CPU time to do it's work.
That's what Thread.Join does, it blocks your calling thread until the Joined thread terminates. I guess I don't know why you're using join if you simply want to Invoke on another thread. As was stated before, code would help clarify the situation.
You can poll ThreadState in order to check the state of your threads vs using a Join if your implementation won't allow for you to block your main thread.
It sounds like you almost want the cancellation pattern. Try this TPL option:
CancellationTokenSource cts = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
if(cts.Token.IsCancellationRequested)
return;
// Do Stuff
});
You can basically fire off a task for the operation you want to do, and if you need to cancel it, you can simply call
cts.Cancel();
Your example is pretty convoluted; having a thread spun off to invoke some method has nothing to do with the original thread.
I am having a problem, for which I am not able to find a solution. The problem is as follows:
In the main thread (the default thread), I am starting a thread and then immediately in the main thread, I wait for the thread's exit by calling Thread.Join on the spawned thread. When I do that if the spawned thread tries to callback in the main thread's context by calling Dispatcher.Invoke, it hangs. Any ideas how I can allow the callback?
The callback has the logic to signal the thread to exit. Without executing the callback, the thread will never exit, and so the main thread is also stuck.
What's the point of starting a new thread if you just wait for it to complete ? Just do the work on the main thread...
I'm not exactly sure what you are asking but you may try BeginInvoke instead of Invoke
If you're only going to be waiting on the thread to terminate, you could simply have a polling loop, like this:
// var otherThread = ...;
volatile bool terminate = false;
while (!terminate)
{
Thread.Sleep(100);
}
otherThread.Join();
Then, leave it up to the callbacks to set the terminate flag to true once you're ready to join.
I had a similar problem which I finally solved in this way:
do{
// Force the dispatcher to run the queued operations
Dispatcher.CurrentDispatcher.Invoke(delegate { }, DispatcherPriority.ContextIdle);
}while(!otherthread.Join(1));
This produces a Join that doesn't block because of GUI-operations on the other thread.
The main trick here is the blocking Invoke with an empty delegate (no-operation), but with a priority setting that is less than all other items in the queue. That forces the dispatcher to work through the entire queue. (The default priority is DispatcherPriority.Normal = 9, so my DispatcherPriority.ContextIdle = 3 is well under.)
The Join() call uses a 1 ms time out, and re-empties the dispatcher queue as long as the join isn't successful.