Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在这种情况下需要锁吗?_C#_Multithreading_Locking - Fatal编程技术网

C# 在这种情况下需要锁吗?

C# 在这种情况下需要锁吗?,c#,multithreading,locking,C#,Multithreading,Locking,在多线程应用程序中是否有必要保护对引用类型的单个变量的访问?我当前锁定该变量,如下所示: private readonly object _lock = new object(); private MyType _value; public MyType Value { get { lock (_lock) return _value; } set { lock (_lock) _value = value; } } 但我想知道这是否真的有必要?给字段赋值不是原子的吗?如果我不锁在这个

在多线程应用程序中是否有必要保护对引用类型的单个变量的访问?我当前锁定该变量,如下所示:

private readonly object _lock = new object();
private MyType _value;
public MyType Value
{
  get { lock (_lock) return _value; }
  set { lock (_lock) _value = value; }
}
但我想知道这是否真的有必要?给字段赋值不是原子的吗?如果我不锁在这个箱子里会出什么问题吗


注意:MyType是一个不可变的类:所有字段都在构造函数中设置,不会更改。若要更改某些内容,将创建一个新实例并将其分配给上述变量。

这取决于多个线程是否访问该属性。有些变量被称为原子操作,在这种原子操作的情况下,不需要使用锁。对不起,英语不好


在您的情况下,不可变,我认为锁是不必要的。

这里有一个关键字。没有它是否安全取决于场景。但是编译器可以做到,比如重新组织操作顺序。因此,即使对一个字段进行读/写操作也可能不安全。

这可能是一个问题。你要关心的不仅仅是作业本身。由于缓存的原因,如果不锁定,并发线程可能会看到对象的旧版本。因此,是否需要锁将取决于您如何使用它,而您不会显示这一点


下面是一个详细解释这个问题的例子

原子化是远远不够的

我通常希望得到一个变量的最新值,而不是潜在地看到一个过时的值——因此读写都需要某种内存障碍。锁是实现这一点的简单方法,其代价是可能由于争用而损失一些性能


我曾经相信,在这种情况下,让变量波动就足够了。我不再相信这是事实。基本上,当涉及共享数据时,我现在尽量避免编写无锁代码,除非我能够使用真正理解这些内容的人(例如Joe Duffy)编写的构建块。

此外,正如您在中所说,甚至不能保证分配是原子的(取决于内存对齐)@Jon,“最新vs stale”有点模糊,不确定。我的意思是,即使它是完全锁定和保护的,您通过读取获得的值对于操作系统进程切换算法的随机行为来说也是有害的。。。它可以在另一个“并发”写之前运行你的读线程,或者相反。。。这类问题超出了我们通常认为的多线程问题的范围。如果它是重要的,它需要用一些其他的机制来管理。。。没有?这就是为什么我现在的代码使用锁的原因。但是,如果原子化就足够了,并且数据是否稍微过时(毫秒?)也无关紧要呢?在我的例子中,这个变量读了很多,但每半小时才写一次。我同意Jon的观点。这里有一篇文章提供了更多信息:另外,谷歌为乔·达菲的博客服务。他是微软的架构师,负责.NET4中的并行扩展。他写了很多关于无锁和低锁模式的文章。不过,主题是低锁比看起来要难得多。@Tommy:这不一定是稍微过时的问题。在某些情况下,如果没有内存屏障,变量的“true”值将永远不会被再次读取。。。你会永远过时的,我错了。更正了链接。我将添加:
volatile
不会在所有情况下解决问题。C#不是我的专长,但IIUC volatile在这种情况下会起作用。volatile(对于C#)确实在读取时获取内存顺序,在写入时释放内存,这就是您在这里需要的。Tony,volatile将帮助编写指针本身,但不需要假设它指向的结构的版本。例如,请参阅我对您其他评论的回复。C#编译器从不重新排序任何内容;你必须担心的是处理器。假设我问你“门上的锁有必要吗?”你很可能会回答说我没有描述门或门要执行的任务。如果不加锁就无法完成发明车门所要执行的任务,则必须在车门上加锁。没有人能告诉您变量设计的任务是否可以在没有锁的情况下实现,除非您告诉他们该任务是什么。详细完整地解释变量可用于的每个可能的线程场景,以及您希望在每个场景中出现的语义。对象是否不可变与此无关。变量是可变的;这就是为什么它们被称为“变量”。它不是“缓存”。它是对挂起的读/写缓冲区中指令的重新排序。相似但不相同的事情。大多数CPU中的缓存是一致的。这是值被写入第一个缓存的顺序。Tony,你说的是指令重写是对的,而缓存不是错的。对于多个CPU,每个CPU都有自己的缓存,不能保证在锁之外保持一致。参见,例如:对不起;错误的链接。尝试