在C ++中,我教会使用volatile关键字变量(myVar),即使在关键部分也可以使用不同的线程。但是对于C#我在MSDN中读到这个奇怪的短语: “volatile修饰符通常用于多个线程访问的字段,而不使用lock语句来序列化访问。” 这句话是否意味着如果我处于锁定状态,那么不需要使用volatile关键字?如果是,那么还有一个问题:可能我必须锁定exect这个变量(myVar)?
Object a = new Object();
double i,k;
Thread1()
{
lock(a)
{
i++;// using variable i.
k++;// using variable k.
}
}
Thread2也这样做。 我和k不易挥发,或者我必须这样做是否安全?:
lock(i)
{
i++;// using variable i.
}
lock(k)
{
k++;// using variable k.
}
答案 0 :(得分:6)
在C ++中,我被教导使用volatile变量(myVar)的volatile关键字,即使在关键部分也可以从不同的线程使用
无论你教过谁,这都不是在教导你整个故事。 C ++中的Volatile不能保证读取或写入具有获取或释放语义!所有易失性保证是编译器不会生成elides读取或无序读写的代码。 单独使用Volatile不足以确保多线程中的正确语义,除非您的编译器对“volatile”对其意味着什么做出了额外的声明。
volatile修饰符通常用于多个线程访问的字段,而不使用lock语句来序列化访问。“这句话是否意味着如果我处于锁定状态,那么不需要使用volatile关键字?
正确。在C#中,volatile 通过插入适当的半栅栏来引入获取和释放语义。由于锁引入了完整的栅栏,因此在读取锁中的字段时不需要volatile。
可能我必须锁定exect此变量(myVar)?
所有这些代码都是完全破碎和错误的,以至于无法回答这个问题。 ++对双打很危险,在C#中使双精灵易失甚至不合法,你无法锁定值类型。
答案 1 :(得分:3)
在标准C ++中,volatile
与线程无关,尽管显然微软的编译器赋予它一些特殊含义。对于像计数器这样的东西,请使用std::atomic<int>
;不需要单独的锁。
答案 2 :(得分:0)
正确,在lock
下的C#中,您不需要使用volatile
,因为使用lock
可以保证所有线程都能看到最新的值。
我同意你的看法,这在MSDN文档中并不清楚:lock
仅用于提供对代码块的互斥访问,但此外它还具有其他线程安全特性,例如:确保每个线程看到相同的值,这在lock
中是固有的,因为它使用了内存屏障。
你的第二个问题是不可能的 - 你必须在引用类型上lock
- 假设你这样做了,在这两种情况下你操作都是“线程安全的”,只要对变量的所有其他读写操作都锁定相同的实例,通常更细粒度的对象更好,所以当他们想要更新别的东西并且必须获得相同的锁时,你不必让其他线程等待,但你可能知道这些变量总是一起被访问,在这种情况下共享锁会更有效率。