Joe Duffy给出了描述CLR 2.0+内存模型的6条规则(它是实际的实现,而不是任何ECMA标准)我正在写下我试图解决这个问题的方法,主要是作为橡皮避短的一种方式,但如果我犯了一个错误在我的逻辑中,至少有人能够在它引起我悲伤之前抓住它.
我试图理解这些规则.
x = y
y = 0 // Cannot move before the previous line according to Rule 1.
x = y
z = 0
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load 0
store z
Run Code Online (Sandbox Code Playgroud)
看看这个,看起来负载0可以在加载y之前向上移动,但是存储可能根本不会被重新排序.因此,如果一个线程看到z == 0,那么它也会看到x == y.
如果y是易失性的,那么加载0在加载y之前不能移动,否则它可能会移动.挥发性商店似乎没有任何特殊属性,没有商店可以相互重新订购(这是一个非常有力的保证!)
完全障碍就像沙子中的一条线,装载和存储不能移动.
不知道规则5的含义.
我认为规则6意味着如果你这样做:
x = y
x = z
Run Code Online (Sandbox Code Playgroud)
然后CLR可以删除y的加载和x的第一个存储.
x = y
z = y
// equates …Run Code Online (Sandbox Code Playgroud) 我正在使用原子(双)比较和交换指令实现无锁机制,例如cmpxchg16b
我目前正在汇编中编写它,然后将其链接进去.但是,我想知道是否有办法让编译器自动为我执行此操作?例如,带有'原子级'的环绕代码块,并让它弄清楚如何将代码实现为底层处理器体系结构中的原子指令(或者如果底层arch不支持它,则在编译时生成错误)?
PS我知道gcc有一些内置函数(至少对于CAS)
http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Atomic-Builtins.html#Atomic-Builtins
我发现了单个生产者 - 单个消费者的几个实现,但是没有针对多个生产者 - 单个消费者的实现.
Delphi是否存在"多个生产者 - 单个消费者"的无锁队列?
我有一个关于以下代码示例的问题(m_value不是volatile,每个线程都在一个单独的处理器上运行)
void Foo() // executed by thread #1, BEFORE Bar() is executed
{
Interlocked.Exchange(ref m_value, 1);
}
bool Bar() // executed by thread #2, AFTER Foo() is executed
{
return m_value == 1;
}
Run Code Online (Sandbox Code Playgroud)
在Foo()中使用Interlocked.Exchange是否保证在执行Bar()时,我会看到值"1"?(即使值已存在于寄存器或缓存行中?)或者在读取m_value的值之前是否需要设置内存屏障?
另外(与原始问题无关),声明一个volatile成员并通过引用InterlockedXX方法传递它是否合法?(编译器警告通过引用传递volatile,所以在这种情况下我应该忽略警告吗?)
请注意,我不是在寻找"更好的做事方式",所以请不要发布建议完全替代方式("使用锁定"等)的答案,这个问题来自于纯粹的兴趣..
从我在锁定免费编程上收集到的内容来看,这是非常难以做到的......我同意.只是想一些问题会让我头疼.但我想知道的是,为什么没有广泛使用高级包装器(例如无锁队列和类似的东西)?例如,boost没有锁定免费库,但据我所知,有人建议使用.我的意思是我猜有很多应用程序,你不能避免关键部分是负载的重要部分.那么原因是什么?是吗...
所以我的问题是:为什么使用无锁编程的高级抽象不是很受欢迎,而同时"常规"多线程编程是"在"?
编辑:boost有一个无锁lib :)
请考虑以下情形:
要求:
程序序列(伪代码):
流程A(生产者):
int bufferPos = 0;
while( true )
{
if( isBufferEmpty( bufferPos ) )
{
writeData( bufferPos );
setBufferFull( bufferPos );
bufferPos = ( bufferPos + 1 ) % M;
}
}
Run Code Online (Sandbox Code Playgroud)
流程B(消费者):
int bufferPos = 0;
while( true )
{
if( isBufferFull( bufferPos ) )
{
readData( bufferPos );
setBufferEmpty( bufferPos );
bufferPos = ( bufferPos + 1 ) % M;
}
}
Run Code Online (Sandbox Code Playgroud)
现在这个古老的问题:如何有效地同步它们!? …
大多数CPU架构都会重新订购存储加载操作,但我的问题是为什么?我对商店装载障碍的解释如下:
x = 50;
store_load_barrier;
y = z;
Run Code Online (Sandbox Code Playgroud)
此外,与发布和获取语义相比,我没有看到这种障碍如何在无锁编程中有多大用处.
我正在尝试将std::strings放入boost::lockfree::queues中,以便我的线程可以使用新数据相互更新.
当我尝试使用时boost::lockfree::queue<std::string> updated_data;,g++说:
在'class boost :: lockfree :: queue>'的实例化中:
错误:静态断言失败:(boost :: has_trivial_destructor :: value)
错误:静态断言失败:(boost :: has_trivial_assign :: value)
我一般都会看到这些错误意味着什么,但我自己也没有希望自己解决这个问题,因为我几乎是c ++的新手.
有没有另一种方法在线程之间传递文本数据lockfree?如果不是,请告诉我如何把std::string成boost::lockfree::queue.
我理解ABA问题.但我无法理解的是:他们说在有自动垃圾收集的语言中它可能无法展示.所以我的问题是:
假设该体系结构可以以无锁的方式为std :: atomic支持8字节标量。为什么标准库不为8字节以下的结构提供类似的专业化知识?
这种std :: atomic专门化的简单实现可以std::memcpy将结构序列化/反序列化为等效形式std::uintx_t,其中xstruct的宽度以位为单位(四舍五入为最接近的2的幂,大于或等于2的整数)。结构的宽度)。这将很好地定义,因为std :: atomic要求这些结构是可微复制的。
例如。https://godbolt.org/z/sxSeId,这里Something只有3个字节,但实现调用__atomic_load和__atomic_exchange都使用锁表。