我不确定我是不理解还是文件没有明确制定.
以下摘录摘自最新草案(N3126,第29.6节):
bool atomic_compare_exchange_weak(volatile A* object, C * expected, C desired);
bool atomic_compare_exchange_weak(A* object, C * expected, C desired);
bool atomic_compare_exchange_strong(volatile A* object, C * expected, C desired);
bool atomic_compare_exchange_strong(A* object, C * expected, C desired);
bool atomic_compare_exchange_weak_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_weak_explicit(A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_strong_explicit(volatile A* object, C * expected, C desired, memory_order success, memory_order failure);
bool atomic_compare_exchange_strong_explicit(A* object, C * expected, …Run Code Online (Sandbox Code Playgroud) 我从许多来源读到这个volatile关键字 在多线程场景中没有帮助 .但是,这个断言一直受到接受指针的原子操作函数的挑战.volatile
例如,在Mac OS X上,我们有OSAtomic函数系列:
SInt32 OSIncrementAtomic(volatile SInt32 *address);
SInt32 OSDrecrementAtomic(volatile SInt32 *address);
SInt32 OSAddAtomic(SInt32 amount, volatile SInt32 *address);
// ...
Run Code Online (Sandbox Code Playgroud)
似乎volatileWindows 上的关键字类似于Interlocked操作:
LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend);
LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend);
Run Code Online (Sandbox Code Playgroud)
似乎在C++ 11中,原子类型具有volatile修饰符的方法,它必须以某种方式表示volatile关键字与原子性有某种关系.
那么,我错过了什么?为什么操作系统供应商和标准库设计者坚持使用volatile关键字进行线程化,如果它没用?
我有一个带有原子成员变量的类:
struct Foo
{
std::atomic<bool> bar;
/* ... lots of other stuff, not relevant here ... */
Foo()
: bar( false )
{}
/* Trivial implementation fails in gcc 4.7 with:
* error: use of deleted function ‘std::atomic<bool>::atomic(const td::atomic<bool>&)’
*/
Foo( Foo&& other )
: bar( other.bar )
{}
};
Foo f;
Foo f2(std::move(f)); // use the move
Run Code Online (Sandbox Code Playgroud)
移动构造函数应该怎么样?
GCC 4.7不喜欢我的任何企图(如添加std::move()周围other.bar)和净是出奇的安静这里...
通常,C++中引用计数智能ptr类的最广为人知的实现,包括标准std::shared_ptr,使用原子引用计数,但不提供对同一智能ptr实例的原子访问.换句话说,多个线程可以安全地在shared_ptr指向同一共享对象的单独实例上操作,但是多个线程不能安全地读取/写入同一shared_ptr实例的实例而不提供某种同步,例如互斥或其他.
已经提出了shared_ptr被称为" atomic_shared_ptr" 的原子版本,并且已经存在初步实现.据推测,可以使用自旋锁或互斥锁轻松实现,但也可以实现无锁实现.atomic_shared_ptr
在研究了其中一些实现后,有一件事是显而易见的:实现无锁std::shared_ptr是非常困难的,并且似乎需要这么多compare_and_exchange操作才能让我质疑简单的自旋锁是否会实现更好的性能.
实现无锁引用计数指针如此困难的主要原因是因为在读取共享控制块(或共享对象本身,如果我们讨论的是侵入式共享指针)之间总是存在竞争,并修改引用计数.
换句话说,您甚至无法安全地读取引用计数,因为您永远不知道其他某个线程何时释放了引用计数所在的内存.
因此,通常,采用各种复杂策略来创建无锁版本.这里的实现看起来像是使用双引用计数策略,其中有"本地"引用计算并发访问shared_ptr实例的线程数,然后是"共享"或"全局"引用,它们计算指向shared_ptr实例的数量到共享对象.
考虑到所有这些复杂性,我真的很惊讶地找到了Dobbs博士的文章,从2004年开始,(在C++ 11原子之前的方式)似乎无情地解决了整个问题:
http://www.drdobbs.com/atomic-reference-counting-pointers/184401888
看起来作者声称能够以某种方式:
"... [读取]指向计数器的指针,递增计数器,并以这样的方式返回指针 - 所有其他线程都不会导致错误的结果"
但我真的不明白他实际实现这一点的方式.他正在使用(非便携式)PowerPC指令(LL/SC原语lwarx和stwcx)将其关闭.
执行此操作的相关代码是他所谓的aIandF"(原子增量和提取)",他将其定义为:
addr aIandF(addr r1){
addr tmp;int c;
do{
do{
tmp = *r1;
if(!tmp)break;
c = lwarx(tmp);
}while(tmp != *r1);
}while(tmp && !stwcx(tmp,c+1));
return tmp;
};
Run Code Online (Sandbox Code Playgroud)
显然,addr …
我试着寻找这方面的细节,我甚至阅读了关于互斥和原子的标准......但我仍然无法理解C++ 11内存模型的可见性保证.据我所知,互斥BESIDE互斥的一个非常重要的特点是确保可见性.Aka每次只有一个线程增加计数器是不够的,重要的是线程增加了最后使用互斥锁的线程所存储的计数器(我真的不知道为什么人们在讨论时不再提这个互斥,也许我有坏老师:)).所以从我可以告诉原子并不强制立即可见性:(来自维护boost :: thread并已实现c ++ 11线程和互斥库的人):
具有memory_order_seq_cst的fence不会强制立即查看其他线程(并且MFENCE指令也不会).C++ 0x内存排序约束只是---排序约束.memory_order_seq_cst操作形成一个总顺序,但对该顺序没有任何限制,除了它必须由所有线程达成一致,并且它不得违反其他排序约束.特别是,如果线程按照与约束一致的顺序看到值,则线程可能会在一段时间内继续看到"陈旧"值.
而且我很好.但问题在于我无法理解C++ 11关于原子的构造是"全局的",而且只能确保原子变量的一致性.特别是我了解以下内存排序中的哪些(如果有的话)保证在加载和存储之前和之后将有一个内存栅栏:http: //www.stdthread.co.uk/doc/headers/atomic/memory_order. HTML
从我可以告诉std :: memory_order_seq_cst插入mem屏障,而其他只强制执行某些内存位置上的操作的顺序.
所以有人可以清楚这一点,我认为很多人会使用std :: atomic制作可怕的错误,如果他们不使用默认值(例如std :: memory_order_seq_cst内存排序),
那么就是2.如果我是对的,那就意味着第二行是此代码中的冗余:
atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);
Run Code Online (Sandbox Code Playgroud)
3. std :: atomic_thread_fences在某种意义上与互斥量具有相同的要求,为了确保非原子变量的seq一致性,必须执行std :: atomic_thread_fence(std :: memory_order_seq_cst); 在load和std :: atomic_thread_fence(std :: memory_order_seq_cst)之前;
经过商店?
是的
{
regularSum+=atomicVar.load();
regularVar1++;
regularVar2++;
}
//...
{
regularVar1++;
regularVar2++;
atomicVar.store(74656);
}
Run Code Online (Sandbox Code Playgroud)
相当于
std::mutex mtx;
{
std::unique_lock<std::mutex> ul(mtx);
sum+=nowRegularVar;
regularVar++;
regularVar2++;
}
//..
{
std::unique_lock<std::mutex> ul(mtx);
regularVar1++;
regularVar2++;
nowRegularVar=(74656);
}
Run Code Online (Sandbox Code Playgroud)
我想不是,但我想确定.
编辑:5.可以断言?
只存在两个线程.
atomic<int*> p=nullptr;
Run Code Online (Sandbox Code Playgroud)
第一个线程写
{
nonatomic_p=(int*) malloc(16*1024*sizeof(int));
for(int i=0;i<16*1024;++i) …Run Code Online (Sandbox Code Playgroud) 我知道volatile允许可见性,AtomicInteger允许原子性.所以,如果我使用volatile AtomicInteger,是否意味着我不必再使用任何同步机制?
例如.
class A {
private volatile AtomicInteger count;
void someMethod(){
// do something
if(count.get() < 10) {
count.incrementAndGet();
}
}
Run Code Online (Sandbox Code Playgroud)
这线程安全吗?
假设我们有两个线程,一个是在循环中读取bool而另一个可以在特定时间切换它.我个人认为这应该是原子的,因为sizeof(bool)在C++中是1个字节而你不是部分读/写字节但我想100%肯定.
那么是或否?
编辑:
另外供将来参考,同样适用于int?
什么(如果有的话)是x86 asm xchg指令的C#等价物?
有了这个命令,哪个imo是一个真正的交换(不像Interlocked.Exchange),我可以简单地自动交换两个int,这就是我真正想做的事情.
更新:
示例代码基于我的建议.变量后缀"_V"被装饰为volatile:
// PART 3 - process links
// prepare the new Producer
address.ProducerNew.WorkMask_V = 0;
// copy the current LinkMask
address.ProducerNew.LinkMask_V = address.Producer.LinkMask_V;
// has another (any) thread indicated it dropped its message link from this thread?
if (this.routerEmptyMask[address.ID] != 0)
{
// allow all other bits to remain on (i.e. turn off now defunct links)
address.ProducerNew.LinkMask_V &= ~this.routerEmptyMask[address.ID];
// reset
this.routerEmptyMask[address.ID] = 0;
}
// PART 4 - swap
address.ProducerNew = …Run Code Online (Sandbox Code Playgroud) 我正考虑在我的应用程序中使用Amazon DynamoDB,我对其原子计数器的可靠性有疑问.
我正在构建一个分布式应用程序,它需要同时并一致地增加/减少存储在Dynamo属性中的计数器.我想知道Dynamo的原子计数器在一个繁重的并发环境中是多么可靠,其中并发级别非常高(例如,平均速率为20k并发命中率 - 获得这个想法,这将是近52亿增量/每月递减).
柜台应该是超级可靠的,永远不会错过任何一个.有人在这样的关键环境中测试了DynamoDB吗?
谢谢
两种常见的锁定习语是:
if (!atomic_swap(lockaddr, 1)) /* got the lock */
Run Code Online (Sandbox Code Playgroud)
和:
if (!atomic_compare_and_swap(lockaddr, 0, val)) /* got the lock */
Run Code Online (Sandbox Code Playgroud)
其中val可能只是一个常量或锁定的新潜在所有者的标识符.
我想知道的是x86(和x86_64)机器上的两者之间是否存在任何显着的性能差异.我知道这是一个相当广泛的问题,因为单个cpu模型之间的答案可能差异很大,但这是我要求的原因之一,而不仅仅是我可以访问的几个cpus的基准测试.