在C# .net6中,等待任务完成会导致线程结束(中断)该线程。

huangapple go评论78阅读模式
英文:

await task completion in a thread ends (breaks) this thread in C# .net6

问题

在线程函数中使用await时遇到问题。似乎await会中断线程。以下是一个演示这一点的测试类。

public class Question {
    public static async Task<double> testTask() {
        // [2]
        await Task.Run(() => {
            Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
            for (int i = 0; i < 100; i++) {
                Task.Delay(10).Wait();
            }
            Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        });

        return 42.00;
    }

    static async Task ThreadFunction() {
        Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        // [1]
        //double x = await test.testTask().ConfigureAwait(true);
        double x = await test.testTask();

        int inserted = 0;
        for (long i = 0; i < 100; i++)
            System.Threading.Thread.Sleep(100);

        // [3]
        Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
    }

    public static void startTestThread() {
        Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        Thread TestThread = new Thread(() => ThreadFunction());
        TestThread.Start();
        TestThread.Join();
        // [4]
        Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}

startTestThread() 在外部调用,作为一个控制台应用程序,没有主函数。

当程序执行到 double x = await test.testTask(); 时,线程"ThreadFunction"返回。这是我不理解的地方。线程应该等待函数testTask()完成。虽然函数被调用并且任务已经开始,但线程却被中断了。所以程序执行顺序不是:1 2 [3] [4],而是:1 2 [4],所以[3] 处的代码没有执行。为什么会这样?非常感谢社区的帮助。

英文:

have a problem when using await in a thread function.
It seems that await breaks the thread. Below the test class to demonstrate this.

    public class Question {
    public static async Task&lt;double&gt; testTask() {
        // [2]
        await Task.Run(() =&gt; {
            Console.WriteLine(&quot;start testTask {0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
            for (int i = 0; i &lt; 100; i++) {
                Task.Delay(10).Wait();
            }
            Console.WriteLine(&quot;end testTask {0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        });

        return 42.00;

    }

    static async Task ThreadFunction() {
        Console.WriteLine(&quot;ThreadFunction begin tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        // [1]
        //double x = await test.testTask().ConfigureAwait(true);
        double x = await test.testTask();


        int inserted = 0;
        for (long i = 0; i &lt; 100; i++)
            System.Threading.Thread.Sleep(100);

        // [3]
        Console.WriteLine(&quot;ThreadFunction end tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
    }


    public static void startTestThread() {

        Console.WriteLine(&quot;start startTestThread. tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        Thread TestThread = new Thread(() =&gt; ThreadFunction());
        TestThread.Start();
        TestThread.Join();
        // [4]
        Console.WriteLine(&quot;end startTestThread. tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}

startTestThread() is called from outside, a console application
in the new manner without a main function.

When program reaches
double x = await test.testTask();
Thread "ThreadFunction" returns.
Rhis is what i do not understand.
The thread should wait for function
testTask()
to get completed. The function is called and Task started
but the thread gets interrupted.
So the program execution sequence is not:
1 2 [3] [4]
instead it is:
1 2 [4]

, so code at [3] not executed. Why is this so? Many thanks to the community

答案1

得分: 3

你在许多地方都缺少了 asyncawait

此外,使用 Thread.Start 来运行一个 Task 是完全错误的,因为线程会在第一个 await 处结束。如果你想同步运行它,应该使用 Task.RunWait,但请注意,如果设置了 SynchronizationContext(在控制台应用程序中通常不会这样),可能会导致死锁。

理想情况下,你不应该在异步代码中执行同步操作。阅读一下这篇这篇文章,了解为什么这是一个不好的做法。

public class Question
{
    public static async Task<double> testTask()
    {
        // [2]
        await Task.Run(async () => {   // async HERE!!
            Console.WriteLine("start testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
            for (int i = 0; i < 100; i++) {
                await Task.Delay(10);     // await HERE!!
            }
            Console.WriteLine("end testTask {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        });

        return 42.00;
    }

    static async Task ThreadFunction()
    {
        Console.WriteLine("ThreadFunction begin tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        // [1]
        //double x = await test.testTask().ConfigureAwait(true);
        double x = await test.testTask();

        int inserted = 0;
        for (long i = 0; i < 100; i++)
            await Task.Delay(100);  // await HERE!!

        // [3]
        Console.WriteLine("ThreadFunction end tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
    }

    public static void startTestThread() {

        Console.WriteLine("start startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
        Task.Run(ThreadFunction).Wait();
        // [4]
        Console.WriteLine("end startTestThread. tid={0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}

我不清楚你尝试使用 ManagedThreadId 测试什么,但这很可能没有用。如果在使用带有 await 的任务时,你不应该关心自己在哪个线程上,同步上下文会处理这个问题。如果你正在使用线程,那么当然会保持在同一个线程上,因为你仍然在同一个函数调用中。

英文:

You are missing async and await in various places.

Furthermore, using Thread.Start to run a Task is wrong on so many levels: the thread will finish as soon as you hit the first await. Instead, if you want to run it synchronously, use Task.Run and Wait, but note that you may get a deadlock if you have a SynchronizationContext set up (not usually the case in a console app).

Ideally you shouldn't do sync-over-async ever. Take a read of this and this article for may reasons why this is a bad idea.

public class Question
{
    public static async Task&lt;double&gt; testTask()
    {
        // [2]
        await Task.Run(async () =&gt; {   // async HERE!!
            Console.WriteLine(&quot;start testTask {0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
            for (int i = 0; i &lt; 100; i++) {
                await Task.Delay(10);     // await HERE!!
            }
            Console.WriteLine(&quot;end testTask {0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        });

        return 42.00;
    }

    static async Task ThreadFunction()
    {
        Console.WriteLine(&quot;ThreadFunction begin tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        // [1]
        //double x = await test.testTask().ConfigureAwait(true);
        double x = await test.testTask();

        int inserted = 0;
        for (long i = 0; i &lt; 100; i++)
            await Task.Delay(100);  // await HERE!!

        // [3]
        Console.WriteLine(&quot;ThreadFunction end tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
    }

    public static void startTestThread() {

        Console.WriteLine(&quot;start startTestThread. tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
        Task.Run(ThreadFunction).Wait();
        // [4]
        Console.WriteLine(&quot;end startTestThread. tid={0}&quot;, System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}

I have no idea what you are trying to test with ManagedThreadId but it's unlikely to be useful. If using tasks with await then you shouldn't care which thread you are on, the synchronization context will sort that out. And if you were using threads then of course you remain on the same thread, you are still in the same function call.

huangapple
  • 本文由 发表于 2023年7月6日 21:04:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76629153.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定