2013-05-01 91 views
7

我知道在java中,如果你有多个线程访问一个未标记为volatile的变量,你可能会得到一些意想不到的行为。C#和java的volatile关键字的行为方式是一样的吗?

例子:

private boolean bExit; 

while(!bExit) { 
    checkUserPosition(); 
    updateUserPosition(); 
} 

如果标记bExit变量voilatile,这将gaurantee其他线程将看到最新的值。

c#的行为方式是否一样?

更新

例如,在C#中,如果你这样做:

int counter = ...; 

for(...) 
{ 
    new Thread(delegate() 
    { 

     Interlocked.Decrement(ref counter); 
    } 
} 


if(counter == 0) 
{ 
    // halt program 
} 

在上面,在C#中,你必须标记计数器变量挥发性或本会工作如预期?

+1

每个* runtime *(JVM或CLR内存模型)都有一组不同的规则,并且有一些重叠。考虑在两种语言/运行时间和比较中查找“volatile”的正确(和不正确)用法。 – user2246674 2013-05-01 20:07:54

+0

C#volatile实际上是保留在低内存应用程序中使用的,应该只能用作绝对最后的手段。下面是一些文档,以C#的形式来看看:http://msdn.microsoft.com/en-us /library/x13ttww7(v=vs.71).aspx – Nomad101 2013-05-01 20:09:08

+1

@ Nomad101 - 我不确定低内存应用程序和volatile关键字之间存在什么关系。 – hatchet 2013-05-01 20:15:46

回答

0

如果标记bExit变量voilatile,这将gaurantee其他 线程将看到最新的值。 c#的行为是否一样?


是的,但都取决于你如何访问共享变量。作为你的例子,如果你以线程安全的方式访问变量如Interlocked.Decrement即使没有使用voilatile也不会成为问题。

volatile (C# Reference from MSDN)

挥发性关键字表示一个字段可能通过 被同时执行多个线程进行修改。声明为volatile的字段 不受制于编译器优化, 假定由单个线程访问。 这可确保最多的 最新值始终存在于现场

What is the "volatile" keyword used for?

+0

因此,我理解无w/o volatile是正确的,当读取一个非易失性变量正在更新我的多个线程? – loyalflow 2013-05-01 20:23:35

+1

我读过volatile,实际上并没有做很多人认为它的作用。我建议阅读http://www.albahari.com/threading/part4.aspx#_The_volatile_keyword – hatchet 2013-05-01 20:27:16

0

你需要小心一点这里你已经在你的例子选择了两个不同的类型。我的一般经验法则是volatile最适合布尔和其他一切,你可能需要其他类型的同步机制。在C#和java中,使用易失性布尔值在例如停止循环或任务执行,其具有从多个线程能见度:

class Processor 
{ 
    private volatile Boolean _stopProcessing = false; 

    public void process() 
    { 
     do 
     { ... } 
     while (!_stopProcessing); 
    } 

    public void cancel() 
    { 
     _stopProcessing = true; 
    } 
} 

上面将在C#或Java并且在该示例工作volatile关键字意味着在处理方法中的读取将与实际的电流值而不是缓存的值。编译器或VM可能会选择否则允许缓存该值,因为循环进程不会更改_stopProcessing本身。

所以对你的第一个问题的答案是肯定的。

虽然你可以在int上使用volatile,但这只有在你只读或写单个值时才有用。只要你做了更复杂的事情,例如递增,你需要一些其他类型的同步,比如你使用互锁。但在第二个例子中,您仍在读取计数器的值,而没有进行任何同步,所以您实际上依赖于其他计数器的使用方式(例如,使用“互锁”)。

在你的第二个例子中,你仍然最好将你的int标记为volatile,这样你再次可以确定你获得了当前值而不是一些缓存版本。但是单独使用volatile是不够的,因为底部的读取可能会与标准递减(counter--)重叠,而不是正确使用Interlocked。

相关问题