线程安全性阅读两次Guid

时间:2019-02-11 22:01:56

标签: c# .net guid

我正在两次读取Guid对象,一次是在if语句中,一次是在if语句的块中。

在C语言中,我将在本地复制变量,以确保if语句内的读取操作不会读取其他值(如果另一个线程在其间更改了该值)。

我怀疑以下方法是a)线程安全的,并且b)会给我相同的值:

public class MyClass {

private Guid MyProp {get;set;} = Guid.Empty; //May be changed at will

public OnRunLoop() //Gets called periodicaly on a thread
{

    var ALocalCopyOfTheProp = MyProp; //Copy locally
    if(ALocalCopyOfTheProp == AValueFromAnotherPlace) //Read 1
    {
        ...

        var AnotherReadOfTheVariable = ALocalCopyOfTheProp; //Read 2

    }

    ...
}

C#.NET本来就不具备谷歌搜索功能,那么在这种情况下,最佳做法是什么?

编辑: -请注意,在这种情况下,MyProp不在我的控制范围内。我不能使用锁,因为该属性来自其他地方。 (对于此事,请您谅解) -Guid是结构而不是引用类型

2 个答案:

答案 0 :(得分:6)

  

在C语言中,我将在本地复制变量,以确保if语句内的读取操作不会读取其他值(如果另一个线程在其间更改了该值)。

我注意到,这种技术只是交换了一个问题-不一致的读取-换成另一个问题-过时的读取。

这种技术在C#中的多线程事件处理程序中很常见;您经常看到类似这样的内容:

var myEvent = this.MyEvent;
if (myEvent != null) myEvent(whatever);

尽管这确实解决了this.MyEvent与调用之间if之间变化的竞争状况问题,但并不能解决更深层次的问题:您可以在一个线程上进行检查,设置事件处理程序在另一个线程上为null,现在假设将不再调用该事件处理程序是 false ,因为将在另一个线程上调用陈旧的值!

您不能简单地在本地复制内容并希望获得最好的结果。您必须证明,使任意数量的线程上进行的任何可能的读和写重新排序都会生成一个明智的程序。

  

Guid对象是引用类型

绝对不是。

  

C#.NET本来就不具备谷歌搜索功能,那么在这种情况下,最佳做法是什么?

拿出锁。

  

我不能使用锁

然后,您只需要在单个线程上调用属性即可。

答案 1 :(得分:1)

Guid是struct(值类型),其大小比原子读取的值长(取决于OS(What operations are atomic in C#?),该值是32或64位。

因此,如果可以从其他线程更改值,则无法以线程安全的方式读取(或写入)Guid值。必须通过某种同步机制(即Guid)来保护访问lock(包括读和写)的代码。

或者,如果您可以保证在对该字段进行所有可能的写入之前(基本上使该字段不可变)不会发生读取,则可以不加锁地读取它。如果同一字段可能有多个写线程,则始终需要保护对Guid值的写操作。