【问题标题】:Stopwatch elapsed time thread safety秒表经过时间线程安全
【发布时间】:2013-05-04 07:01:11
【问题描述】:

好的,我有一个相当简单的问题,我找不到简明的答案。我想知道在读取 Stopwatch 的 elapsed 属性时是否需要担心调用 lock() 语句,而它仍在运行。

也是一个Stopwatch,我应该用它来测量线程的运行时间。我读过其他类似的问题,可以使用DispatchTimer。我也研究过使用事件,但是对于如此简单的事情来说似乎有很多开销,请告诉我这是否完全错误并且我应该使用事件。一些简单的代码来说明我在说什么。

 class foo
 {
      private bool _isRunning { get; set; }
      private Stopwatch sw { get; set; }
      public void StartThread()
      {
          this._isRunning = true;
          new Thread(new ThreadStart(this.DoWork)).Start();
          this.sw.Restart();
      }     
      public void StopThread()
      {
          this._isRunning = false;
          this.sw.Stop();
      }
      private void DoWork()
      {
          while(this._isRunning)
          {
               //Do Stuff
          }
      }
      public TimeSpan GetRuntime()
      {
          return this.sw.Elapsed;
      }
      public foo()
      {
          _isRunning = false;
          sw = new Stopwatch();
      }
 }

假设在使用上述类的应用程序中,我要在停止 Stopwatch 之前从不同的线程调用 GetRuntime() 是否需要添加 lock() 语句以确保获得正确的数据,并且我不会阻止Stopwatch 继续运行。或者我认为它不需要lock() 并且会很好。

我确实理解理论上您可以根据需要运行任意数量的读取,我只是好奇地看到 Elapsed 属性后备存储是否会不断被写入是否改变了事情。我已经阅读了很多关于线程安全的信息,但我只是在寻找一个澄清和确认我确实在考虑这个问题。

【问题讨论】:

标签: c# .net multithreading thread-safety


【解决方案1】:

MSDN documentation 声明,关于秒表,“不保证任何实例成员都是线程安全的。”请注意,这里肯定存在理论上的漏洞,因为它在内部使用“长”滴答计数,并且在 32 位处理器上更新 long 不是原子操作。您可能会看到部分更新(因此损坏)的值。您可能不会注意到,直到 Ticks 恰好超过 32 位边界,此时您可能会遇到一个非常意外的罕见错误(您可能会读取 Int32.MaxValue,后跟 0,然后是 Int32.MaxValue + 1,如果您在错误的时刻查询它,则会在经过的时间上产生非常大的差异。)

【讨论】:

  • 好吧,我对此提出质疑是对的。感谢您提供的信息,但只是一点说明,如果我坚持只使用 32 位返回值我会没问题,或者您是说即使 32 位返回也是基于 64 位后备存储的?我知道 64 位值可能导致只读取一半正确值,这就是出现这个问题的原因。
  • @Nomad101,我怀疑在内部,一切都是根据滴答计数计算的。我绝对不会依赖其他操作是线程安全的,因为这是一个实现细节,文档不保证。
  • @Nomad101:文档说不保证是线程安全的。问“好吧,如果我只坚持这部分功能集,是否安全?”然后将影响安全和正确性的决策基于可能发生变化的实施细节。你对线程安全的态度不应该是“我能逃脱的最危险的操作是什么?”而是“我如何保证我可以安全地访问这个数据结构?”
  • @Nomad101:您问“如果我坚持使用 32 位返回值,我可以吗?”文档没有说“如果你坚持使用 32 位返回值,那么操作是线程安全的”。它说的是相反的:不保证是线程安全的。问“好吧,如果我坚持这种特定的使用模式,它是线程安全的吗?”表示您正在考虑尝试做一些危险的事情。
  • @EricLippert 我也可以在上下文中复制和粘贴,看看这个。在评论的开头,“谢谢你的信息,但是只是一点点澄清”,在评论的最后,“我知道 64 位值可能导致只读取一半的正确值,这就是为什么这个问题来了起来。”,那么我到底在哪里说我要做一些危险的事情,或者现在要求澄清说你要做一些事情?
猜你喜欢
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2016-05-15
相关资源
最近更新 更多