我需要帮助理解与关系的同步。我读的越多,试图理解的例子,我越觉得我什么都不懂。有时候我觉得这就是它,我已经知道了,但在看了另一个例子之后我再次感到困惑。请帮我把它搞定。
如果A是某个原子变量m的存储,则表示操作A与操作B同步,具有释放语义,B是来自同一变量m的加载,具有获取语义,B读取存储的值由A. 还有人说操作A发生在操作B之前,如果
行。如果我们看一下这个例子
thread0执行| thread1执行
存储x(发布)|加载x(获取)
存储到x这里同步 - 来自x的负载吗?如果我们确实在这里有同步关系,那么在从x加载之前就存储到x,所以在线程0中存储到x之前排序的所有内容都会发生 - 在从线程1中的x加载之前发生。这意味着这里有强制排序。这样对吗?但在这种情况下,我不明白“和B读取A存储的值”的定义是什么意思?如果线程1比线程0快,则它可以读取旧值。那么这里的关系是什么,是否有任何关系?如果没有,我该如何提供这种关系呢?
提前致谢。
答案 0 :(得分:5)
我不能说我对术语很熟悉,但这就是我认为的方法。我将使用.NET定义作为术语:“如果其他处理器在任何后续操作的影响之前总是看到它的效果,则操作具有获取语义。如果其他处理器在效果之前将看到每个先前操作的效果,则操作具有释放语义操作本身。“
示例中的商店和加载之间没有强制排序。任何一个都可以先执行。在加载之前执行存储操作时与B同步。发生这种情况时,保证在执行加载(获取)之后的操作之前执行存储(发布)之前的所有操作。
然而,可以在商店之前执行加载操作。在这种情况下,A不与B同步(因为条件“和B读取由A存储的值”不是真的),因此加载后的操作可以在存储之前的操作之前执行。订单含糊不清。
发布语义保证对于x的某个值,我们将知道在我们能够在第二个线程中加载相同的存储值之前(在我们能够执行下面的操作之前)将执行存储之前的操作负载)。
假设count和flag初始化为零,并且两个线程并行运行:
thread0:
st count, 1 (A)
st.release flag, 1 (B)
thread1:
ld.acquire flag (C)
ld count (D)
我们知道A发生在B和C发生之前 - 发生在D之前,因为它们的顺序是由发布强制并获取语义。 B和C的顺序是不确定的。它只在B与C同步时才被定义,然后我们知道A发生在D之前(在A发生之前 - 在B发生之前 - 在C发生之前 - 在D之前)。
在thread1中,如果flag为1,则计数始终为1.如果flag为0,则计数可以为0或1.我们可以测试该标志以确定另一个线程是否已将值设置为计数。
如果没有获取和释放语义,可以重新排序加载和存储,并且标志和计数可以是0或1,彼此之间没有依赖关系。
如果我们想确保在C之前发生B,我们可以使用信号量或其他一些等待和信号机制。在前面的例子中,我们可以通过忙等待标志来强制执行订单。
thread1:
ld.acquire flag (C)
repeat C while flag == 0
ld count (D)