通过lock语句内存屏障 [英] Memory Barrier by lock statement
问题描述
我最近读到内存壁垒和重新排序的问题,我现在有一些关于它的困惑
考虑以下情形:
私有对象_object1 = NULL;
私有对象_object2 = NULL;
私人布尔_usingObject1 = FALSE;
私有对象为MyObject
{
得到
{
如果(_usingObject1)
{
返回_object1;
}
,否则
{
返回_object2;
}
}
组
{
如果(_usingObject1)
{
_object1 =价值;
}
,否则
{
_object2 =价值;
}
}
}
私人无效更新()
{
_usingMethod1 = TRUE;
SomeProperty = FooMethod();
// ..
_usingMethod1 = FALSE;
}
-
在
更新
方法;在_usingMethod1 = TRUE
语句总是获取或设置属性之前执行的?或由于重新排序问题,我们能不能保证? -
如果我们使用
挥发性
像私人挥发性布尔_usingMethod1 = FALSE;
-
如果我们使用
锁;
我们可以保证再锁内的每一个语句才能等来执行:私人无效FooMethod()
{
对象更衣室=新的对象();
锁(柜)
{
X = 1;
Y = A;
I ++;
}
}
记忆障碍的主题是相当复杂的。它甚至绊倒了专家不时。当我们谈论一个内存屏障,我们真的是结合两种不同的思路。
- 获取围栏:内存屏障中,其他读取和放大器;写不准动的前的围栏
- 发布栅栏:A内存屏障中,其他读取和放大器;写不准动的之后的围栏。
这将创建一个内存屏障只有两个一个是有时也被称为的半护栏的。创建两个有时也被称为内存屏障的全栅栏的
的
挥发性
关键字创建半围栏。挥发性领域具有读取语义收购而写有释放的语义。这意味着没有指令可以读取之前或写操作后移动。
的
锁定
关键字创建全栅栏两个边界(入口和出口)。这意味着没有指令可以每个边界之前或之后进行移动。
然而,这一切都没有实际意义,如果我们只关注一个线程。订货,因为它是由该线程感知,总是保留。事实上,如果没有这个基本机制保障没有程序将永远工作的权利。真正的问题是用的其他的主题是如何看待的读取和写入。 。这就是你需要关心
因此,要回答你的问题:
-
从单一线程的角度来看......是的。从另一个线程的角度看...没有。
-
这要看情况。这可能工作,但我需要有更好的理解你正在试图acheive什么。
-
从另一个线程的角度看...没有。的读取和写入可自由锁定的边界内移动。他们只是无法将这些范围之外移动。这就是为什么它是其他线程同时创建内存屏障重要的。
I read recently about memory barriers and the reordering issue and now I have some confusion about it.
Consider the following scenario:
private object _object1 = null;
private object _object2 = null;
private bool _usingObject1 = false;
private object MyObject
{
get
{
if (_usingObject1)
{
return _object1;
}
else
{
return _object2;
}
}
set
{
if (_usingObject1)
{
_object1 = value;
}
else
{
_object2 = value;
}
}
}
private void Update()
{
_usingMethod1 = true;
SomeProperty = FooMethod();
//..
_usingMethod1 = false;
}
At
Update
method; is the_usingMethod1 = true
statement always executed before getting or setting the property? or due to reordering issue we can not guarantee that?Should we use
volatile
likeprivate volatile bool _usingMethod1 = false;
If we use
lock;
can we guarantee then every statement within the lock will be executed in order like:private void FooMethod() { object locker = new object(); lock (locker) { x = 1; y = a; i++; } }
The subject of memory barriers is quite complex. It even trips up the experts from time to time. When we talk about a memory barrier we are really combining two different ideas.
- Acquire fence: A memory barrier in which other reads & writes are not allowed to move before the fence.
- Release fence: A memory barrier in which other reads & writes are not allowed to move after the fence.
A memory barrier that creates only one of two is sometimes called a half-fence. A memory barrier that creates both is sometimes called a full-fence.
The volatile
keyword creates half-fences. Reads of volatile fields have acquire semantics while writes have release semantics. That means no instruction can be moved before a read or after a write.
The lock
keyword creates full-fences on both boundaries (entry and exit). That means no instruction can be moved either before or after each boundary.
However, all of this moot if we are only concerned with one thread. Ordering, as it is perceived by that thread, is always preserved. In fact, without that fundamental guarentee no program would ever work right. The real issue is with how other threads perceive reads and writes. That is where you need to be concerned.
So to answer your questions:
From a single thread's perspective...yes. From another thread's perspective...no.
It depends. That might work, but I need to have better understanding of what you are trying to acheive.
From another thread's perspective...no. The reads and writes are free to move around within the boundaries of the lock. They just cannot move outside those boundaries. That is why it is important for other threads to also create memory barriers.
这篇关于通过lock语句内存屏障的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!