6

Is it possible to make sure that a task runs on another thread than the main thread? So that this piece of code would not bock the calling thread?

var task = Task.Run(() =>
{
    //third party code i don't have access to
    Thread.Sleep(3000);
});

I know that there is Task.Delay but I want to make sure that the task will run on another thread.

thalm
  • 2,738
  • 2
  • 35
  • 49
  • 1
    I may be wrong so follow my logic: [`Task.Run`](https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.run(v=vs.110).aspx) "Queues the specified work to run on the ThreadPool", I *assume* this is [The Managed Thread Pool](https://msdn.microsoft.com/en-us/library/0ka9477y(v=vs.110).aspx), which says: "Thread pool threads are background threads". Therefore, all `Task.Run` calls will spawn the thread on a background thread. I assume the `Main` thread is always a foreground thread, if so `Task.Run` will never be on the Main thread. Check with `Thread.CurrentThread.IsBackground`. – Quantic Jan 09 '17 at 19:46
  • thanks for the info, i will investigate on it. i was assuming that the task may or may not run on another thread, depending on what the task scheduler thinks is right. so i was looking for a was to make sure that it is another thread. but if you are right, then this is always the case. – thalm Jan 09 '17 at 19:51
  • 1
    The only way it could run on the main thread is if you wait for it from the main thread before it has started executing (via [task inlining](https://blogs.msdn.microsoft.com/pfxteam/2009/10/15/task-wait-and-inlining/)). Other than that, it will execute on the thread pool. – Douglas Jan 09 '17 at 19:51

4 Answers4

11

I think that there are different ways to accomplish what you are trying. But based on what you are trying to do, I think that you would be fine just using async/await which is not going to block your UI for sure, and will allow you to control your task asynchronously.

As MSDN says:

Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method. The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.

https://msdn.microsoft.com/en-us/library/mt674882.aspx

This is an example of usage:

public async Task MyMethodAsync()
{
    Task<int> runTask = RunOperationAsync();

    int result = await longRunningTask;

    Console.WriteLine(result);
}

public async Task<int> RunOperationAsync()
{
    await Task.Delay(1000); //1 seconds delay
    return 1;
}

This won´t block your UI

NicoRiff
  • 4,803
  • 3
  • 25
  • 54
  • thanks, for the example, but i do not want to use Task.Delay, that is the point of the whole question. how would it work with Thread.Sleep? – thalm Jan 09 '17 at 19:46
  • @thalm in this case using async/await Task.Delay has the same usage of Thread.Sleep but that would not block your main thread. Take a look at this Jon Skeet answer http://stackoverflow.com/a/13430126/637840 – NicoRiff Jan 09 '17 at 19:51
  • 1
    the problem is that the Thread.Sleep is in user generated code i don't have access to. i can't change it to Task.Delay... – thalm Jan 09 '17 at 19:53
  • 1
    well ok, that´s another scenario. This, in my opinion, the best way to handle that if you control all the code. If you don´t have access to the 'user generated code', then you probably be better using ThreadPool or BackgroundWorker. – NicoRiff Jan 09 '17 at 20:01
2

@Nico is correct in that ideally, you could use asynchronous programming all the way. That approach is ideal because it doesn't waste a thread sleeping (or, in a more realistic example, blocking on I/O).

Is it possible to make sure that a task runs on another thread than the main thread?

Yes. Task.Run will always queue work to the thread pool, and the main (entry point) thread is never a thread pool thread.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
0

Use the thread pool.

    static void Main(string[] args)
    {
        ThreadPool.QueueUserWorkItem(o => { Thread.Sleep(5000); Console.WriteLine("Threadpool task done."); });
        for( int i = 0; i < 10; i++)
        {
            Console.WriteLine("Main thread: {0}", i);
            Thread.Sleep(1000);
        }

        Console.ReadLine();
    }

The output should look like this: enter image description here

dviljoen
  • 1,612
  • 1
  • 16
  • 28
-2

Your current code should work, but you will need to call the Start() method on the task to invoke it.

You could also accomplish this through threading:

new System.Threading.Thread(() => {
    System.Threading.Thread.Sleep(500);
}).Start();
Peter
  • 674
  • 6
  • 14
  • 3
    Creating threads should be avoided as much as possible, since reusing the ones that have already been created is **way** more cheap than creating a new one. Take a look at [Why so much difference in performance between Thread and Task?](http://stackoverflow.com/questions/13125105/why-so-much-difference-in-performance-between-thread-and-task) – appa yip yip Jan 09 '17 at 20:04