C# 如何在执行下一个代码之前等待线程完成?

C# 如何在执行下一个代码之前等待线程完成?,c#,async-await,C#,Async Await,我需要这样的代码: module.StopAndWait(); module.DoSmth(); module.Resume(); 我已经编写了类异步模型。我有一个问题,而线!是的;。在这一行,程序冻结。我认为必须改变,但事实并非如此。 我试着把它声明为易变的。 但无论如何,程序在运行时有问题!是的 public class AsyncModel { bool run = false; bool isStopped; public async void Run()

我需要这样的代码:

module.StopAndWait();
module.DoSmth();
module.Resume();
我已经编写了类异步模型。我有一个问题,而线!是的;。在这一行,程序冻结。我认为必须改变,但事实并非如此。 我试着把它声明为易变的。 但无论如何,程序在运行时有问题!是的

public class AsyncModel
{
    bool run = false;
    bool isStopped;
    public async void Run()
    {
        if (run) return;
        await Task.Run(() => progr());
    }
    public void StopAndWait()
    {
        run = false;
        while (!isStopped) ;// <-- Problem
    }
    void progr()
    {
        isStopped = false;
        run = true;

        while (run)
        {
            Thread.Sleep(1500);
        }

        isStopped = true;
    }
}

似乎您的问题可以通过使用普通的旧同步代码轻松解决。另外,尝试使用Task.Delay而不是Thread.Sleep。最后,方法命名的一致性

我假设这段代码试图运行一个可以在后台取消的循环。 实现这一点的简单方法是使用CancellationTokenSource和CancellationToken,例如:

void progr(CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        // Do something expensive
    }
}
请注意,progr没有对外部字段的引用。它所需要的只是那个标记

CancellationTokenSource应该在任务本身开始之前创建

Task thatTask;
CancellationTokenSource cts;

public void StartTheJob()
{
    cts=new CancellationTokenSource();
    thatTask=Task.Run(()=>progr(cts.Token));
}
要停止任务,只需调用cts即可。取消

要添加延迟,请使用等待任务。延迟。。。而不是“线程。睡眠”。可以取消,并且不会阻止用于运行任务的线程池线程:

async Task progr(CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        // Do something expensive
        await Task.Delay(1000,token);
    }
}

检查更多信息

当您使用异步方法时,您需要并行性,否则请使用同步方法。为isstoppedvolatile bool isStopped;,指定一个t或f;,试试看,跑步场也是如此。创建自己的线程信号不是一个好主意,在.NET中已经有很好的类用于此,请查看ManualResetEvent/AutoResetEvent,理想情况下,您应该完全使用带有CancellationToken的任务,resume看起来像什么?存在多个问题,例如由于使用变量而没有同步,使用异步无效和竞争条件。主要问题是没有调用Run,所以StopAndWait永远不会完成。如果要等待任务终止,请使用wait。所有这些代码都可以替换为单个等待任务。如果您想在等待之前做一些事情,那么var myTask=Task.Run。。。;某物等待我的任务;。发出取消信号的正确方法是使用CancellationTokenSource并将CancellationToken传递给progr。检查wait Task.Delay1000,令牌;这可能会引发TaskCanceledException,应该捕获并处理它。@TheodorZoulias我知道。如果你知道它的实际用途,你可以为它添加更多的代码。可以使用计时器来执行循环作业,而不是循环作业。不过,这个问题间接地问到了如何正确地取消后台任务。如果有人问如何在后台投票,更好的办法是用计时器或类似的东西,而不是循环。我认为这是一个有趣的问题,但已经有人问过了:我想知道为什么run=false;影响到whilerun。。。但这是真的;暂时不影响!是什么@RomanAleshin从另一个线程修改全局状态的任何尝试都需要同步以避免随机结果,但在这种情况下,async void是另一个严重的问题-async void仅适用于事件处理程序。这意味着该方法是一个不可等待的fire-and-forget方法,任务可能会在完成之前被垃圾收集。甚至不能保证任务会在应用程序退出之前启动。该行为true;可能根本不会跑。改为使用异步任务,并至少将任务存储在变量或字段中
async Task progr(CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        // Do something expensive
        await Task.Delay(1000,token);
    }
}