I am using Task to create and perform some operations by a different thread, once the operation is done I also have called back to be called.
System.Threading.Tasks.Task.Factory.StartNew(() =>
this._httpService.CreateRecord(new Uri(Configuration.Current.CreateRecordUrl), httpObj)).ContinueWith(
(response) =>
{
if (!response.IsFaulted)
{
if (httpObj.CallBack != null)
{
httpObj.CallBack(response.Result);
}
}
else {
this._logger.Error("There was some error which causes the task to fail");
}
});
My console application's main thread is not waiting for the Task thread to complete, because it's background thread.
How can I make task thread foreground thread?
Thanks
StartNew() method returns a Task instance. Calling Wait() method on the returned task will block the main thread until the task finishes.
static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
// ...
});
task.Wait(); // The main application thread waits here until the task returns
}
My console application's main thread is not waiting for the Task thread to complete, because it's background thread.
Your application is not waiting for the task, because you don't tell it to do so.
As others have already stated, use Wait/Result or await to wait for the task, depending on whether you're in an asynchronous context or not.
How can i make task thread foreground thread.
Most likely you don't want to do that in the first place. A background thread is a thread that terminates when all foreground threads have ended. Thread pool threads are inherently background threads, if you actually want to schedule your task to a foreground thread, that is, a thread that will keep the app process alive even if the main thread is finished, you'll have to create your own TaskScheduler. That, btw, would be a reason to use Task.Factory.StartNew. If you don't need Task.Factory.StartNew, go for Task.Run.
You should wait for completion of the Task in your main thread.
Change your code to
var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
this._httpService.CreateRecord(new Uri(Configuration.Current.CreateRecordUrl), httpObj)).ContinueWith(
(response) =>
{
if (!response.IsFaulted)
{
if (httpObj.CallBack != null)
{
httpObj.CallBack(response.Result);
}
}
else {
this._logger.Error("There was some error which causes the task to field");
}
});
task.Wait(); // Wait till your Task has finished.
The Wait() method has some overloads to specify how long to wait. Also you have to add some exception handling if Task execution fails due to an exception of cancellation.
Try creating a fresh new Thread instead of taking from the pool. For eg:
Thread t = new Thread(()=>
{
//all your code goes here
});
t.IsBackground = false; //by default it will be foreground. so don't need this line in your case
t.Start();
This will create a foreground thread for u and it will make sure the thread completes its execution.
Related
I wonder why in a console app, if I spin a new thread to run from Main, even though Main will reach the end it will wait, though if I spin up a new task, it will exit and not wait for the task to end.
e.g.
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(SomeMethod));
t.Start();
// Main will wait, and app won't close until SomeMethod finishes
}
vs.
static void Main(string[] args)
{
Task.Run(() => SomeMethod());
// Main will close / app shuts down without waiting for SomeMethod to finish
}
When reading the documentation for the Thread.IsBackground property, you'll notice there are two types of threads, background and foreground:
... background threads do not prevent a process from terminating. Once all foreground threads belonging to a process have terminated... any remaining background threads are stopped and do not complete.
The reason why the Thread constructor prevents the Main process from terminating is because by default, it creates foreground threads, while task-based asynchronous operations automatically execute on the ThreadPool, which uses background threads by default, and will allow the process to terminate before they are completed.
You have set SomeMethod to run on a different thread so it's now asynchronous. You aren't waiting for the result so Main will just continue and just exit, killing both threads in the process.
Use:
Task.Run(async () => await SomeMethod());
Assuming SomeMethod is awaitable otherwise you can just await the result externally
Task.Run(() => SomeMethod()).Result;
Task t = new Task(() =>
{
//I would expect this to be on a worker thread, but it's not!
Thread.Sleep(1000);
});
Task test = new Task(() =>
{
Thread.Sleep(1000);
});
test.ContinueWith(x =>
{
//Do some UI Updates here, but also start another Task running.
t.Start();
}, TaskScheduler.FromCurrentSynchronizationContext());
test.Start();
Why does t gets invoked on the UI Thread. I understand that I created a continuation Task against test which correctly gets called on the UI thread, but I am then starting a new task running. Now I know I could get around this by specifying TaskScheduler.Default as an overload method against t.Start, but why does a new Task get started on the ui thread?
but why does a new Task get started on the ui thread?
Because unless specified otherwise calling Start on a task schedules the task on the current TaskScheduler which in your case is a just facade over the UI thread's SynchronizationContext that you created using TaskScheduler.FromCurrentSynchronizationContext().
Starts the Task, scheduling it for execution to the current TaskScheduler.
From Task.Start Method
If you want that task to be scheduled on a different TaskScheduler than the current one you can pass it as a parameter:
t.Start(TaskScheduler.Defualt);
Note: There's almost no case imaginable that using Task.Start is the best solution for. You should probably rethink this avenue.
Don't use the Task.Start method. Also, if you want to delay a task use Task.Delay like this:
Task.Delay(TimeSpan.FromSeconds(1)) //Wait 1 second
.ContinueWith(t => DoSomeUIWork(), TaskScheduler.FromCurrentSynchronizationContext()) //execute something on the UI thread
.ContinueWith(t => DoSomeBackgroundWork()); //Then do some background work
Can someone please explain why this creates a deadlock, and how to solve it?
txtLog.AppendText("We are starting the thread" + Environment.NewLine);
var th = new Thread(() =>
{
Application.Current.Dispatcher.Invoke(new Action(() => // causes deadlock
{
txtLog.AppendText("We are inside the thread" + Environment.NewLine); // never gets printed
// compute some result...
}));
});
th.Start();
th.Join(); // causes deadlock
// ... retrieve the result computed by the thread
Explanation: I need my secondary thread to compute a result, and to return it to the main thread. But the secondary thread must also write debug informations to the log; and the log is in a wpf window, so the thread needs to be able to use the dispatcher.invoke(). But the moment I do Dispatcher.Invoke, a deadlock occurs, because the main thread is waiting for the secondary thread to finish, because it needs the result.
I need a pattern to solve this. Please help me rewrite this code. (Please write actual code, do not just say "use BeginInvoke"). Thank you.
Also, theoretically, I don't understand one thing: a deadlock can only happen when two threads access two shared resources in different orders. But what are the actual resources in this case? One is the GUI. But what is the other? I can't see it.
And the deadlock is usually solved by imposing the rule that the threads can only lock the resources in a precise order. I've done this already elsewhere. But how can I impose this rule in this case, since I don't understand what the actual resources are?
Short answer: use BeginInvoke() instead of Invoke().
Long answer change your approach: see the altenative.
Currently your Thread.Join() is causing that main thread get blocked waiting for the termination of secondary thread, but secondary thread is waiting to main thread executes your AppendText action, thus your app is deadlocked.
If you change to BeginInvoke() then your seconday thread will not wait until main thread executes your action. Instead of this, it will queue your invocation and continues. Your main thread will not blocked on Join() because your seconday thread this time ends succesfully. Then, when main thread completes this method will be free to process the queued invocation to AppendText
Alternative:
void DoSomehtingCool()
{
var factory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
factory.StartNew(() =>
{
var result = await IntensiveComputing();
txtLog.AppendText("Result of the computing: " + result);
});
}
async Task<double> IntensiveComputing()
{
Thread.Sleep(5000);
return 20;
}
This deadlock happens because the UI thread is waiting for the background thread to finish, and the background thread is waiting for the UI thread to become free.
The best solution is to use async:
var result = await Task.Run(() => {
...
await Dispatcher.InvokeAsync(() => ...);
...
return ...;
});
The Dispatcher is trying to execute work in the UI message loop, but that same loop is currently stuck on th.Join, hence they are waiting on each other and that causes the deadlock.
If you start a Thread and immediately Join on it, you definitely have a code smell and should re-think what you're doing.
If you want things to be done without blocking the UI you can simply await on InvokeAsync
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.
I really liked #user5770690 answer. I created an extension method that guarantees continued "pumping" or processing in the dispatcher and avoids deadlocks of this kind. I changed it slightly but it works very well. I hope it helps someone else.
public static Task PumpInvokeAsync(this Dispatcher dispatcher, Delegate action, params object[] args)
{
var completer = new TaskCompletionSource<bool>();
// exit if we don't have a valid dispatcher
if (dispatcher == null || dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished)
{
completer.TrySetResult(true);
return completer.Task;
}
var threadFinished = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(async (o) =>
{
await dispatcher?.InvokeAsync(() =>
{
action.DynamicInvoke(o as object[]);
});
threadFinished.Set();
completer.TrySetResult(true);
}, args);
// The pumping of queued operations begins here.
do
{
// Error condition checking
if (dispatcher == null || dispatcher.HasShutdownStarted || dispatcher.HasShutdownFinished)
break;
try
{
// Force the processing of the queue by pumping a new message at lower priority
dispatcher.Invoke(() => { }, DispatcherPriority.ContextIdle);
}
catch
{
break;
}
}
while (threadFinished.WaitOne(1) == false);
threadFinished.Dispose();
threadFinished = null;
return completer.Task;
}
I thought one of the points about async/await is that when the task completes, the continuation is run on the same context when the await was called, which would, in my case, be the UI thread.
So for example:
Debug.WriteLine("2: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
await fs.ReadAsync(data, 0, (int)fs.Length);
Debug.WriteLine("3: Thread ID: " + Thread.CurrentThread.ManagedThreadId);
I would NOT expect this:
2: Thread ID: 10
3: Thread ID: 11
What gives? Why is the thread ID for the continuation different than the UI thread?
According to this article[^] I would need to explicitly call ConfigureAwait to change the behavior of the continuation context!
When you await, by default the await operator will capture the current "context" and use that to resume the async method.
This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. (If there is no currently-running task, then TaskScheduler.Current is the same as TaskScheduler.Default, the thread pool task scheduler).
It's important to note that a SynchronizationContext or TaskScheduler does not necessarily imply a particular thread. A UI SynchronizationContext will schedule work to the UI thread; but the ASP.NET SynchronizationContext will not schedule work to a particular thread.
I suspect that the cause of your problem is that you are invoking the async code too early. When an application starts, it just has a plain old regular thread. That thread only becomes the UI thread when it does something like Application.Run.
The await expression will use the value of SynchronizationContext.Current to return control flow back to the thread on which it occurred. In cases where this is null it will default to the TaskScheduler.Current. The implementation relies solely on this value to change the thread context when the Task value completes. It sounds like in this case the await is capturing a context that isn't bound to the UI thread
By default, Windows Forms sets up the synchronization context when the first control is created.
So you can do like this:
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var f = new Form1();
//var s=SynchronizationContext.Current;
//var s2=TaskScheduler.Current;
GetAsync();
Application.Run(f);
}
static async Task<bool> GetAsync()
{
MessageBox.Show($"thread id {Thread.CurrentThread.ManagedThreadId}");
bool flag = await Task.Factory.StartNew<bool>(() =>
{
Thread.Sleep(1000);
return true;
});
MessageBox.Show($"thread id {Thread.CurrentThread.ManagedThreadId}");
return flag;
}
I have this code :
var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
// Code...
Invoke(new Action(() => progressBar.Increment(1)));
// Code...
});
task.Wait();
But the Invoke fail, without Exception or any kind of error.
It seems that the "wait" prevents the refresh of the form, probably because I'm still in the method.
how do I get around this?
Thanks
You got yourself a dead-lock.
When the Task is running (on a different thread) and you call Invoke, it wants to invoke it on the mainthread. But the mainthread is waiting for the Task to complete... (task.Wait() will block until it's ready)
What if you use:
await task;
The method using this code should be marked as async. The compiler will cut the method into pieces, and while waiting, the messageloop/thread runs again. When the task is ready, the rest of the method will be executed. (below the await task;)
Look here for more info: await vs Task.Wait - Deadlock?
This is a deadlock. The UI thread is blocking on the task.Wait() line, waiting for the task to finish. The task is blocking on Invoke because it needs to tell the UI thread to update the progress bar.
You should NOT be waiting for a task to complete on the UI thread, and should remove task.Wait(). The UI will update as soon as the task finishes.
Any code you were going to put below task.Wait() should go inside the Invoke action:
var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
// do task work
Invoke(new Action(() => {
progressBar.Increment(1);
// other code that needs the task to be finished should go here
}));
});
// don't call task.Wait() here