小编jas*_* na的帖子

c ++ 11注册缓存线程安全

volatile中:多线程程序员最好的朋友,Andrei Alexandrescu给出了这个例子:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};
Run Code Online (Sandbox Code Playgroud)

他说,

... ...编译器得出结论,它可以将flag_缓存在寄存器中...它会损害正确性:在您调用Wait for some Gadget对象之后,虽然另一个线程调用Wakeup,但Wait将永远循环.这是因为flag_的更改不会反映在缓存flag_的寄存器中.

然后他提供了一个解决方案

如果对变量使用volatile修饰符,则编译器不会将该变量缓存在寄存器中 - 每次访问都将访问该变量的实际内存位置.

现在,其他人在stackoverflow和其他地方提到volatile关键字并不真正提供任何线程安全保证,我应该使用std :: atomic或mutex同步,我同意.

但是,以std :: atomic路由为例,内部使用内存栅栏read_acquire和write_release(Acquire和Release Semantics),我看不出它是如何实际修复寄存器缓存问题的.

例如,在x86的情况下,x86/64上的每个加载都意味着获取语义,并且每个存储意味着释放语义,使得x86下的编译代码根本不会发出任何实际的内存屏障.(C++ 11中memory_order_consume的目的)

g = Guard.load(memory_order_acquire);
if (g != 0)
    p = Payload;
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在Intel x86-64上,Clang编译器为此示例生成紧凑的机器代码 - 每行C++源代码一个机器指令.该系列处理器具有强大的内存模型,因此编译器无需发出特殊的内存屏障指令即可实现读取.

所以....现在假设x86 arch,std :: atomic如何解决注册表问题中的缓存?在编译代码中没有用于读取的内存屏障指令,它似乎与常规读取的编译代码相同.

c++ multithreading volatile cpu-registers c++11

6
推荐指数
1
解决办法
638
查看次数

目标c-局部静态变量初始化线程安全吗?

注意:我使用的是Objective-C ++,其中允许使用非编译时常量(/sf/answers/861337081/

+ (Foo)sharedFoo
{ 
    static Foo *foo = [Foo new];
    return foo;
}
Run Code Online (Sandbox Code Playgroud)

静态初始化程序只能运行一次,但是它是否具有线程安全性,例如,如果多个线程同时调用+(Foo)sharedFoo,是否可以保证[Foo new]仅运行一次?

我问是因为如果这样,那么为什么建议obj-C中的单例模式使用如下所示的dispatch_once呢?

+ (Foo)sharedFoo {
    static Foo *foo = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        foo = [Foo new];
    });

    return foo;
}
Run Code Online (Sandbox Code Playgroud)

我本质上是在问为什么第一行不能只是

static Foo *foo = [Foo new];
Run Code Online (Sandbox Code Playgroud)

如果我们知道静态本地var初始化仅运行一次,则只需完全跳过dispatch_once。

编辑:好的,我找到了答案。1.首先,我意识到我使用的是Objective-C ++,它允许上述代码进行编译(并在运行时运行)2.第二,编译器将该代码转换为不带dispatch_once的单例初始化器的“原始”版本,从而使它确实不是线程安全的。

objective-c objective-c++ static-initialization

5
推荐指数
1
解决办法
727
查看次数

如果我有T && temp = std :: move(其他); 然后在接受T值的函数上使用它

所以假设我有以下功能:

void foo(std::string strParam) // pass-by-value
{
    // function-body
}
Run Code Online (Sandbox Code Playgroud)

因此,foo(字符串)的strParam将通过复制(如果arg是左值)或移动(如果arg是rvalue)创建.

众所周知,

foo("blah"); // rvalue; so string move constructor invoked for strParam.
Run Code Online (Sandbox Code Playgroud)

与,

string bar = "blah";
foo(bar); // lvalue; so string copy constructor invoked for strParam.
Run Code Online (Sandbox Code Playgroud)

再次,

string bar = "blah";
foo(move(bar)); // xvalue; so move constructor.
Run Code Online (Sandbox Code Playgroud)

以及命名的右值引用变量

string &&temp = // can be whatever
foo(temp); // *named* rvalue reference IS a lvalue; so copy constructor.
Run Code Online (Sandbox Code Playgroud)

所以我想这意味着什么,

string &&movedBar = move(bar);
foo(movedBar); // it actually invokes copy …
Run Code Online (Sandbox Code Playgroud)

move move-semantics c++11

4
推荐指数
1
解决办法
131
查看次数