2010-08-23 67 views
0

我有一个有很多数据的数据类(电视节目表数据)。 从一侧查询数据并定期从另一侧更新。 有两个线程:第一个线程根据请求查询数据,第二个线程定期更新数据。 为防止锁定,我使用数据类的两个实例(副本):活动实例和备份实例。 最初,两个实例都填充了相同的数据。第一个线程只从实例中读取。 第二个线程定期更新两个实例,如下所示:如何在此模型中使用volatile关键字?

  • 更新备份实例。
  • 交换备份和活动实例(即备份实例成为活动实例)。
  • 更新备份实例。
  • 备份实例和活动实例现在都是最新的。

我的问题是:我应该如何在这里使用volatile关键字?

public class data 
{ 
    // Lots of fields here. 
    // Should these fields also be declared volatile? 
} 

我已经做了引用挥发性:

public volatile data live 
public volatile data backup 
+0

volatile在多线程环境中几乎没用。 http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ – leppie 2010-08-23 12:53:23

+2

@leppie该论文是关于C++中的volatile。虽然我也不倾向于在这里使用volatile,但C#中的volatile不具有相同的语义。 – 2010-08-23 12:59:58

+0

使用* volatile *会使其失败更快。锁是必需的。 – 2010-08-23 13:04:12

回答

0

说实话,我只是锁定它。正确性更容易检查,并且删除了对备份的需求。

随着你的计划在这里,这些领域也必须是不稳定的。考虑其他情况:

public class Data 
{ 
    public int SimpleInt; 
} 

在这里,我们只是一个简单的公共领域,同样适用于更现实的结构。 (顺便提一下,C#中更常见的是类名的captials)。

现在考虑线程A所看到的live.SimpleInt。因为live可以被缓存,所以我们需要把它作为volatile。但是,请考虑当对象与backup交换后再交换回live时,则live将具有与以前相同的内存位置(除非GC已将其移动)。因此live.SimpleInt将具有与之前相同的内存位置,因此如果它不是易失性的,则线程A可能使用缓存版本live.SimpleInt。但是,如果您创建了一个新的Data对象,而不是交换进出,那么新值live.SimpleInt将不在线程的缓存中,并且它可能是安全的非易失性的。

考虑到领域的领域也必须是不稳定的也是很重要的。

确实现在你只需要一个存储的数据对象。新创建的对象只能被一个线程引用(因此它不会被另一个线程损坏或者损坏另一个线程),它的创建将基于从live中读取的值,这对另一个线程来说也是安全的只有阅读(除了一些memoisation技术,这意味着“读取”真的写在幕后,阅读不会损害其他阅读,虽然他们可以被写作伤害)改变,而只有一个线程可见,因此只有最后写需要关心同步的问题,因为只有volatile或用于保护的MemoryBarrier确实应该是安全的,因为分配引用是原子操作,并且您不再关心旧值。

0

我不认为你会通过标记volatile来得到你想要的效果。考虑这个代码。

volatile data live; 

void Thread1() 
{ 

    if (live.Field1) 
    { 
    Console.WriteLine(live.Field1); 
    } 
} 

在上述false的例子可以写入控制台如果所述第二线程调换第一线程进入if和称为Console.WriteLine的时间之间的livebackup引用。

如果这个问题不关心你,那么你真正需要做的就是将live变量标记为volatile。您不需要将data中的各个字段标记为volatile。原因是因为易失性读取创建获取栅栏内存障碍和易失写入创建释放栅栏内存障碍。这意味着当线程2交换引用时,所有写入data的单个字段的写入必须首先提交,并且当线程1想要读取live实例的各个字段时,必须首先从主存储器重新获取live变量。你并不需要标记backup变量volatile,因为它永远不会使用线程1

advanced threading section in Joe Albahari's ebook进入细节上的volatile和语义的大量需要说明为什么你只需要标记您的live参考因此。