You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Stopwatch类中Start方法阻塞导致Stop方法失效的问题?

嘿,我完全懂你的问题——你的Start()方法肯定是卡在一个同步的无限循环里了,导致主线程被死死占住,根本没机会执行后面的Stop()调用!这就像你在终端里跑了个死循环脚本,后面的命令永远轮不到执行,可不就停不下来嘛。

问题根源拆解

你当前的Start()方法应该是类似这样的逻辑(八九不离十):

void Start()
{
    isTurnedOn = true;
    Watch(); // 直接在当前线程调用Watch,而Watch里是while(isTurnedOn)的循环
}

这种情况下,Start()会一直卡在Watch()的循环里,主线程根本走不到sw.Stop()那一行,isTurnedOn自然永远不会被设为false,计时器就停不下来了。

解决方案:用多线程/异步解放主线程

要解决这个问题,核心就是把Watch()里的计时循环放到单独的线程或者异步任务里,让主线程能继续执行后续的Stop()调用。

方案1:用Thread实现(简单直观)

修改你的Stopwatch类,把计时逻辑放到新线程中:

using System;
using System.Threading;

class Stopwatch
{
    // 加volatile确保多线程下能看到最新值
    private volatile bool isTurnedOn;
    private Thread _timerThread;
    private int _elapsedSeconds;

    public void Start()
    {
        isTurnedOn = true;
        _elapsedSeconds = 0;
        // 启动新线程运行Watch逻辑,不阻塞主线程
        _timerThread = new Thread(Watch);
        _timerThread.Start();
        Console.WriteLine("计时器已启动");
    }

    private void Watch()
    {
        while (isTurnedOn)
        {
            Thread.Sleep(1000);
            // 这里加个判断,防止Stop后还多走一次计数
            if (isTurnedOn)
            {
                _elapsedSeconds++;
                Console.WriteLine($"已流逝:{_elapsedSeconds}秒");
            }
        }
    }

    public void Stop()
    {
        isTurnedOn = false;
        // 等待线程安全结束(可选,根据你的需求)
        _timerThread.Join();
        Console.WriteLine($"计时器已停止,总时长:{_elapsedSeconds}秒");
    }
}

class Program
{
    static void Main()
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        // 模拟你需要计时的任务,比如等待3秒
        Thread.Sleep(3000);
        // 现在主线程能顺利调用Stop了!
        sw.Stop();
        Console.ReadKey();
    }
}

方案2:用异步Task实现(更现代的方式)

如果是.NET Core/.NET 5+,用异步任务会更优雅:

using System;
using System.Threading.Tasks;

class Stopwatch
{
    private volatile bool isTurnedOn;
    private Task _timerTask;
    private int _elapsedSeconds;

    public void Start()
    {
        isTurnedOn = true;
        _elapsedSeconds = 0;
        // 用Task.Run把Watch放到后台任务
        _timerTask = Task.Run(Watch);
        Console.WriteLine("计时器已启动");
    }

    private async Task Watch()
    {
        while (isTurnedOn)
        {
            await Task.Delay(1000);
            if (isTurnedOn)
            {
                _elapsedSeconds++;
                Console.WriteLine($"已流逝:{_elapsedSeconds}秒");
            }
        }
    }

    public async Task StopAsync()
    {
        isTurnedOn = false;
        // 等待异步任务完成
        await _timerTask;
        Console.WriteLine($"计时器已停止,总时长:{_elapsedSeconds}秒");
    }
}

class Program
{
    static async Task Main()
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        // 异步等待3秒
        await Task.Delay(3000);
        await sw.StopAsync();
        Console.ReadKey();
    }
}

关键注意点

  • 线程安全:给isTurnedOn加上volatile关键字,确保多个线程能看到这个变量的最新值,避免出现线程缓存导致的逻辑错误。
  • 避免僵尸线程:用Thread.Join()或者await Task等待计时线程/任务结束,确保资源被正确释放。
  • 不要在主线程跑循环:这是你最初问题的核心,任何长时间运行的循环都要放到后台线程或异步任务里,不然主线程会被阻塞。

这样修改后,你的Start()不会再卡住主线程,Stop()就能顺利切换isTurnedOn的状态,计时器也就可以正常停止啦!

内容的提问来源于stack exchange,提问作者ex1t3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:53:31