如何修复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
相关产品推荐
相关产品推荐

