在C++中,原子能遭受虚假存储吗?
例如,假设m和n是原子能和m = 5最初.在主题1中,
m += 2;
Run Code Online (Sandbox Code Playgroud)
在线程2中,
n = m;
Run Code Online (Sandbox Code Playgroud)
结果:最终值n应为5或7,对吧?但它可能是虚假的6吗?它是虚假的4或8,甚至是其他什么?
换句话说,C++内存模型是否禁止线程1表现得好像这样做?
++m;
++m;
Run Code Online (Sandbox Code Playgroud)
或者,更奇怪的是,好像它做到了这一点?
tmp = m;
m = 4;
tmp += 2;
m = tmp;
Run Code Online (Sandbox Code Playgroud)
参考文献:H.-J.Boehm&SV Adve,2008,图1.(如果您点击链接,那么,在论文的第1部分中,查看第一个项目符号项:"......提供的非正式规范")
替代形式的问题
一个答案(赞赏)表明,上述问题可能会被误解.如果有帮助,那么这是另一种形式的问题.
假设程序员试图告诉线程1 跳过操作:
bool a = false;
if (a) m += 2;
Run Code Online (Sandbox Code Playgroud)
C++内存模型是否禁止线程1在运行时表现,就好像它这样做?
m += 2; // speculatively alter m
m -= 2; // oops, should not have altered! reverse the alteration
Run Code Online (Sandbox Code Playgroud)
我问,因为之前联系过的Boehm和Adve似乎解释说多线程执行可以
可编译的示例代码
如果您愿意,这里有一些您可以实际编译的代码.
#include …Run Code Online (Sandbox Code Playgroud) 在C中是否有(POSIX-)可移植方式用于原子变量操作,类似于使用pthread的可移植线程?
原子操作是像"递增和获取"这样的操作,它们以原子方式执行,这意味着没有上下文切换可以干扰操作.在Linux内核空间中,我们必须使用atomic_t类型,在Java中我们有java.util.concurrent.atomic包.
在Linux上,atomic.h文件提供原子操作,但include依赖于平台,例如#include <asm-x86_64/atomic.h>,它在Mac OS X上不能以类似的方式提供.
参考以下链接:http://docs.python.org/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
我想知道以下内容:
(x, y) = (y, x)
Run Code Online (Sandbox Code Playgroud)
将在cPython中保证原子.(x和y都是python变量)
考虑在x86 CPU上进行单个内存访问(单个读取或单个写入,而不是读取或写入)SSE指令.该指令访问16字节(128位)的存储器,访问的存储器位置对齐为16字节.
文档"英特尔®64架构内存订购白皮书"指出,对于"读取或写入地址在8字节边界上对齐的四字(8字节)的指令",内存操作似乎作为单个内存访问执行,而不管记忆类型.
问题:是否存在Intel/AMD/etc x86 CPU,它们保证读取或写入与16字节边界对齐的16字节(128位)作为单个内存访问执行?是这样,它是哪种特定类型的CPU(Core2/Atom/K8/Phenom/...)?如果您对此问题提供答案(是/否),请同时指定用于确定答案的方法 - PDF文档查找,强力测试,数学证明或您用于确定答案的任何其他方法.
此问题涉及http://research.swtch.com/2010/02/off-to-races.html等问题
更新:
我在C中创建了一个可以在您的计算机上运行的简单测试程序.请在您的Phenom,Athlon,Bobcat,Core2,Atom,Sandy Bridge或您碰巧拥有的任何支持SSE2的CPU上编译并运行它.谢谢.
// Compile with:
// gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.
#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;
unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));
void* thread1(void *arg) {
for (int i=0; i<100*1000*1000; i++) { …Run Code Online (Sandbox Code Playgroud) 我需要为另一个线程设置一个标志来退出.另一个线程会不时检查退出标志.我是否必须使用原子作为旗帜或只是一个普通的布尔就足够了(为什么(如果我使用普通布尔可能会出错的例子)?
#include <future>
bool exit = false;
void thread_fn()
{
while(!exit)
{
//do stuff
if(exit) break;
//do stuff
}
}
int main()
{
auto f = std::async(std::launch::async, thread_fn);
//do stuff
exit = true;
f.get();
}
Run Code Online (Sandbox Code Playgroud) 我搜索并发现不可变是线程安全而可变不是.这可以.但是我得到了误导性的注释,博客,关于线程安全的原子与非原子的答案,请给出答案的解释.
假设有一个名为"name"的原子字符串属性,如果[self setName:@"A"]从线程A调用,[self setName:@"B"]从线程B调用,并[self name]从线程C 调用,则不同线程上的所有操作将串行执行,这意味着如果一个线程正在执行setter或getter,然后其他线程将等待.这使得属性"name"读/写安全,但如果另一个线程D [name release]同时调用,则此操作可能会导致崩溃,因为此处不涉及setter/getter调用.这意味着对象是读/写安全(ATOMIC)但不是线程安全的,因为另一个线程可以同时向对象发送任何类型的消息.
如果属性"name"是非原子的,那么上面例子中的所有线程--A,B,C和D将同时执行,产生任何不可预测的结果.在原子的情况下,A,B或C中的任何一个将首先执行,但D仍然可以并行执行.
你对此的评论将有助于我们......
而我的问题是,"这在可可,原子或非原子中是线程安全的吗?"
我有一个类,我想在不同的线程中使用,我想我可以使用std::atomic这种方式:
class A
{
int x;
public:
A()
{
x=0;
}
void Add()
{
x++;
}
void Sub()
{
x--;
}
};
Run Code Online (Sandbox Code Playgroud)
在我的代码中:
std::atomic<A> a;
Run Code Online (Sandbox Code Playgroud)
并在另一个线程中:
a.Add();
Run Code Online (Sandbox Code Playgroud)
和
a.Sub();
Run Code Online (Sandbox Code Playgroud)
但我收到一个a.Add()未知的错误.我怎么解决这个问题?
有没有更好的方法来做到这一点?
请注意,这是一个示例,我想要的是确保对A类的访问是线程安全的,所以我不能使用
std::atomic<int> x;
Run Code Online (Sandbox Code Playgroud)
如何使用线程安全的类std::atomic?
我不确定我是不理解还是文件没有明确制定.
以下摘录摘自最新草案(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) 我有一个带有原子成员变量的类:
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 …