跨线程读取变量的值并不重要

在c#中,是否有一种更新变量(不使用锁)的方法,其中多个线程可以读取值,但更新变量的线程不重要。

我的意思是,如果一个线程更新该值,但其他线程几分钟后没有获得更新的值,那就没问题。

有这样的方式吗?

非常感谢

最好的选择是使用ReaderWriterLockSlim (如果你没有使用.net 3.5,则使用ReaderWriterLock )。 提示: 本教程可以帮助您入门。

如果更新的值对其他线程不重要,为什么变量在线程之间共享? 每个线程都可以使用自己的副本。

我不清楚。 您是否想要故意延迟读取值,或者您是否意味着其他线程无法立即看到更新后的值无关紧要?

在任何情况下,如果你想在没有锁定的情况下自动更新变量,你应该考虑使用Interlocked方法,但我不确定这是否是你需要的。

这取决于你想要做什么。 您可以将该字段标记为易变,但这对您没有任何好处。 例如,我不确定volatile是否会确保递增是一个primefaces操作。 换句话说,您的一个增量(或其他更新)可能会“丢失”(由另一个线程覆盖)。 为此你可以使用Interlocked.Increment 。

再次,它真的取决于你想要做什么。 大多数情况下,使用锁是最容易的。

这听起来像是重新发明缓存机制的迂回方式。 你有没有研究过.NET的许多缓存系统?

您可以使用Interlocked.CompareExchange以primefaces方式更新变量而不锁定,直到您成功为止。 这避免了锁定的开销,同时确保了一致性,下面的伪代码应该这样做,对不起我对C#不太熟悉。

 static void atomic_add(ref int ptr, int addend){ int previous = *ptr; while(1){ int observed = Interlocked.CompareExchange(ptr, previous+addend, previous); if(observed == previous){ break; }else{ previous = observed; } } } 

如果第一个参数指向的值等于第三个参数,CompareExchange将用第二个参数替换第一个参数的值,并在调用CompareExchange时在ptr返回内存中的值。 如果compare exchange返回的值与ptr中观察到的前一个值相同,那么该值已成功更新并且循环中断,否则,指针中的值自上次读取后更改,之前更新,我们再次尝试。

从我所读到的Interlocked.CompareExchange只存在于int32,浮点数和对象(虽然不确定那个是否完全无锁?)。 我想它可以在64位平台上使用更广泛的值,但我没有任何东西支持它。

假设某些线程更新了您的共享变量,如果您不使用任何同步,那么您的其他线程:

  • 可能会立即或不会立即读取更新后的值。 如果没有,他们会在以后阅读
  • 将在短时间内具有不一致的值(一些将获得新值,其他将具有更新的值)

如果这些问题不重要,并且如果您的逻辑不依赖于共享变量的值,则不需要同步。 只允许所有线程访问共享变量。

你想要达到什么目的? 获得更好的答案将会有所帮助。

编辑:

正如ShuggyCoUk所指出的那样,谨慎使用这种方法。 它依赖于primefaces读取和写入,这取决于共享变量的类型。 摘自此处 :

以下数据类型的读取和写入是primefaces的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型。 此外,在先前列表中具有基础类型的枚举类型的读取和写入也是primefaces的。 其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是primefaces的。

我会将数据放入一个不可变的“类”(因此它是一个引用类型)。

如果要更新值,首先要构建一个新实例,然后更新对它的引用(这是一个primefaces操作)。

每个读者线程将获得一致的旧值或一致的新值(取决于它从引用中读取的时间点)。 由于数据类是不可变的,因此无法获得中间结果!

您可能需要查看System.Threading.AutoResetEventSystem.Threading.ManualResetEvent

它允许您跨线程触发事件(值已更改)。 如果你想在更新上保持懒惰, ManualResetEvent可能更合适……

我不确定你是否正在考虑控制对所述变量的访问……在这种情况下,同步方法可以解决这个问题:

 [MethodImpl(MethodImplOptions.Synchronized)] public void Foo() { // Do foo } 

您还可以在修改其值时获取所述对象的锁:

 lock(myObject) { myObject = new value; } 

使用本机primefaces的.Net类型
这取决于您使用的变量类型。 一些变量primefaces地行动。 primefaces写入意味着cpu一次性写入整个变量,或者至少可以认为它是这样做的。 这意味着没有其他线程看到部分更新的变量 – 这显然是坏的! primefaces行为的变量将按照您的要求行事,无需锁定。

对引用类型的赋值,bool,char,byte,sbyte,short,ushort,uint,int和float都是primefaces的。

我在这里得到了primefaces类型列表: http : //social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/a5a3c1b4-9f76-43d7-90a6-6572c59491fe

请参阅此处的C#规范的第5.5节: http : //download.microsoft.com/download/3/8/8/388e7205-bc10-4226-b2a8-75351c669b09/CSharp%20Language%20Specification.doc