.NET线程 - 分配需要锁定

时间:2011-02-23 06:20:22

标签: c# .net multithreading locking

我有一些多线程代码,我想增加一点的性能,所以我想知道我是否可以摆脱锁定。

我有一个现场成员:

private IList<ServerStatus> status;

它在类似的线程中更新:

status = GetUpdatedStatus();

它用在另一个这样的线程中:

var currentStatus = status;

所以问题是,如果没有锁定两个赋值语句,上面会产生任何问题吗?

我想我能看到的唯一场景是currentStatus为null,但是我再次希望赋值在某种程度上是线程安全的(或者它已经更改了引用)

2 个答案:

答案 0 :(得分:20)

你是对的。您将看到作业,否则您将看不到它。引用的赋值(和读取)总是“原子的”(最后它是因为32位机器引用是32位,所以可以原子方式完成,而64位机器(运行64位应用程序)引用是64位,所以可以原子方式完成。唯一的例外是尝试在32位机器上写/读长(64位)。你必须使用Interlocked.Read / Interlocked.Exchange)

通常应将状态声明为volatile,以便每个线程只能看到最新版本。你应该读到这个:http://www.albahari.com/threading/它非常好!

如果您不信任我,请阅读Do We Really Need Locks and Barriers?此处http://www.albahari.com/threading/part4.aspx

部分 啊......我忘记了......世界恨你,所以有一点要知道它的变化:有时它不起作用:-) :-)阅读,在另一页的同一页面例如,The volatile keyword部分,红色框下面的部分。 Notice that applying volatile doesn’t prevent a write followed by a read from being swapped, and this can create brainteasers。最后,唯一可以确定的方法是使用Interlocked.Exchange来编写和Interlocked.CompareExchange来读取内容或者通过同步保护读取和写入部分(如lock)或填写您的使用Thread.MemoryBarrier程序(但不要尝试,你会失败,你甚至不知道为什么)。保证锁定中的所有读取和写入都将在锁定中完成,而不是在锁定之前或之后。

答案 1 :(得分:6)

参考写入保证是原子的,因此只需要检查两件事:

  • 在紧密循环中使用 - 如果您需要注意更改,则可能需要添加volatile
  • 双重更新;如果您(例如)通过引用交换进行添加/删除,则应使用Interlocked.CompareExchange以确保不丢失数据;继续重新应用您的更改,直到您赢得交换

object snapshot, newValue;
do
{
    snapshot = field;

    // do something based on that; create a clone
    // with more/less data for example
    newValue = ...;
} while (!ReferenceEquals(
    Interlocked.CompareExchange(ref field, newValue, snapshot), snapshot));