2014-08-29 56 views
0

我有一个程序,它有一个用户界面。如果我只有一个读写器,并且它不是时间关键的,我需要锁吗?

当用户按下按钮时,程序将加载一些数据,这将花费一分钟左右,所以自然界面将无法更新。

因此,我正在做以下工作 - 我有一个名为“hasLoaded”的布尔变量,加载代码(在它自己的线程上工作)将在完成时设置为true。界面会经常检查并停止显示“加载”屏幕。

问题是 - 因为这是一个共享变量,所以你可能想要锁定它(或者使用读写器纤细的锁或其他东西)。锁显然只是共享变量(“hasLoaded”)。然而自从:

  1. 只有一个读者
  2. 只有一个作家
  3. 这没关系,如果接口读取“错误”的价值,因为它要在第二
  4. 的分数再次检查

我还需要锁吗?澄清 - 如果两个线程同时读取它,是否会发生任何“数据损坏”警告或其他问题,或者是可能发生的“最糟糕的”事情是它读取一次错误的值并选择它下一次正确的时候?

+0

锁定会阻止对跨线程共享的资源执行并发操作。跨线程共享哪些资源,您认为您可能需要锁定? – 2014-08-29 18:35:34

+0

变量本身。对不起,我以为我说得很清楚。我会很快回顾我的问题 – Haedrian 2014-08-29 18:36:14

+2

只需使用[BackgroundWorker](http://msdn.microsoft.com/en-us/library/cc221403(v = vs.95).aspx)并等待它发射它RunWorkerCompleted事件 – Jonesopolis 2014-08-29 18:36:46

回答

1

由于它是一种小于或等于CPU架构的字大小的数据类型,所以您几乎不担心是否会出现数据损坏问题。写入和读取将是原子的。

虽然这不是问题。问题是,在某些情况下,该国旗的读者可能永远不会看到它改变为价值。这实际上很容易用以下代码来演示。您将需要使用Release配置进行编译,并在没有附加调试器的情况下运行它。您可能会发现该程序永远不会有效地证明该错误。

// * Must be compiled as RELEASE and ran outside of a debugger. 
class Program 
{ 
    // Decorate with volatile to change the behavior. 
    static bool stop = false; 

    public static void Main(string[] args) 
    { 
     var t = new Thread(() => 
     { 
      Console.WriteLine("thread begin"); 
      bool toggle = false; 
      while (!stop) 
      { 
       toggle = !toggle; 
      } 
      Console.WriteLine("thread end"); 
     }); 
     t.Start(); 
     Thread.Sleep(1000); 
     stop = true; 
     Console.WriteLine("stop = true"); 
     Console.WriteLine("waiting..."); 

     // The Join call should return almost immediately. 
     // With volatile it DOES. 
     // Without volatile it does NOT. 
     t.Join();   
    } 
} 

在您的具体情况下,这可能实际上是没有争议的。原因是作者是后台线程,读者是UI线程。这是至关重要的,因为内存屏障将保证在后台线程结束时写入被执行,这可能在hasLoad设置为true后立即生效。在UI线程方面,消息泵本身可能会注入一个你不知道的内存屏障。因此,每次您检查hasLoaded的值(推测使用某种计时器)时,您可能会获得最新值。

无论如何,如果它的工作没有锁或使用volatile它是这样做,只是偶然。帮你一个忙,并采取适当的保护措施,并锁定。

更好的是,使用Task结合新的asyncawait关键字。如果做得正确,这可以完成,甚至不需要hasLoaded标志,它也会看起来更优雅。

+0

这做了一个有趣的阅读。几乎是我想要的答案。谢谢。 – Haedrian 2014-08-29 19:07:47

0

你需要声明你的布尔值为volatile。

如上描述MSDN:

挥发性关键字表示一个字段可能通过 被同时执行多个线程进行修改。声明为volatile的字段 不受制于编译器优化, 假定由单个线程访问。这确保了最新的值始终存在于现场。

如果你没有声明它是volatile的,编译器可能会优化你的代码,使得标志的更新永远不会被另一个线程看到。

+0

它被称为“陈旧数据”,虽然它不太可能(取决于实际的代码等),但你是正式的。 – 2014-08-29 18:40:38

-1

你不需要为你的例子锁定布尔值,但是如果你想做一个代码注释来说明你为什么选择不锁定,因为你可能会重新访问这段代码,并对“脏”读取共享的布尔值。

+0

这是错误的。这项手术实际上并不安全。 – Servy 2014-08-29 18:56:39

相关问题