相关疑难解决方法(0)

为什么我们在C++中使用volatile关键字?

可能重复:
C++:什么时候有挥发性关键字帮你?

我从来没有用过它,但我想知道为什么人们会用它?它到底是做什么的?我搜索了论坛,发现它只是C#或Java主题.

c++ volatile compiler-optimization

347
推荐指数
2
解决办法
25万
查看次数

忙等待循环中是否需要内存屏障或原子操作?

考虑以下spin_lock()实现,最初来自这个答案:

void spin_lock(volatile bool* lock)  {  
    for (;;) {
        // inserts an acquire memory barrier and a compiler barrier
        if (!__atomic_test_and_set(lock, __ATOMIC_ACQUIRE))
            return;

        while (*lock)  // no barriers; is it OK?
            cpu_relax();
    }
}
Run Code Online (Sandbox Code Playgroud)

我所知道的:

  • volatile防止编译器*lockwhile循环的每次迭代中优化重新读取;
  • volatile 不插入内存或编译器障碍 ;
  • 这样的实现实际上可以在GCC中工作x86(例如在Linux内核中)和其他一些架构;
  • 至少一个存储器和编译器屏障需要spin_lock()执行针对通用体系结构; 这个例子插入它们__atomic_test_and_set().

问题:

  1. volatile这里是否足够或者是否存在while循环中需要内存或编译器障碍或原子操作的架构或编译器?

    1.1根据C++标准?

    1.2在实践中,对于已知的体系结构和编译器,特别是它支持的GCC和平台?

  2. 在GCC和Linux支持的所有体系结构上,此实现是否安全?(在某些架构上至少效率低下,对吧?)
  3. while根据C++11它的内存模型,循环是否安全?

有几个相关的问题,但我无法从它们构建一个明确和明确的答案:

  • 问:单线程中的内存障碍

    原则上:是的,如果程序执行从一个核心移动到下一个核心,则可能看不到在先前核心上发生的所有写入. …

c++ multithreading gcc spinlock memory-barriers

21
推荐指数
3
解决办法
1924
查看次数

是否可以重新订购对挥发物的访问?

考虑以下对volatile内存的写入顺序,我从David Chisnall在InformIT的文章 "理解C11和C++ 11 Atomics"中获取:

volatile int a = 1;
volatile int b = 2;
             a = 3;
Run Code Online (Sandbox Code Playgroud)

我对C++ 98的理解是,根据C++ 98 1.9,这些操作无法重新排序:

符合实现需要模拟(仅)抽象机器的可观察行为,如下所述...抽象机器的可观察行为是它对易失性数据的读写顺序和对库I/O函数的调用

Chisnall说,对订单保存的约束仅适用于单个变量,写出符合要求的实现可以生成执行此操作的代码:

a = 1;
a = 3;
b = 2;
Run Code Online (Sandbox Code Playgroud)

或这个:

b = 2;
a = 1;
a = 3;
Run Code Online (Sandbox Code Playgroud)

C++ 11重复了C++ 98的措辞

符合实现需要模拟(仅)抽象机器的可观察行为,如下所述.

但这说关于volatiles(1.9/8):

严格根据抽象机器的规则来评估对volatile对象的访问.

1.9/12表示访问volatileglvalue(包括变量a,bc以上)是副作用,1.9/14表示一个完整表达式(例如,一个语句)中的副作用必须先于后面的副作用在同一个线程中完整表达.这使我得出结论,Chisnall显示的两个重新排序是无效的,因为它们不符合抽象机器所规定的排序.

我忽略了什么,还是Chisnall错了?

(请注意,这不是一个线程问题.问题是是否允许编译器重新排序对volatile单个线程中不同变量的访问.)

c++ volatile c++11

11
推荐指数
2
解决办法
1160
查看次数

当仅在中断期间读取变量时需要挥发

C标准规定,当变量的值可能会在程序正常执行流程之外更改时,应在变量的定义中使用volatile关键字。

如果在正常执行流程中更改(写入)了全局变量,并且仅在该正常流程之外(在中断中)读取。这个变量需要可变吗?又为什么呢?

c embedded interrupt volatile

9
推荐指数
1
解决办法
259
查看次数

创建/加入线程时的隐式同步

考虑到创建/加入线程时隐含的同步,该代码工作所需的最小框架是什么??没有?xstd::atomicvolatile

#include <thread>
#include <cassert>
int main() {
    int x = 123; // ***
    std::thread( [ & ] { assert( x == 123 ); x = 321; } ).join();
    assert( x == 321 );
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

c++ multithreading memory-model language-lawyer

8
推荐指数
1
解决办法
336
查看次数

为什么在C#中进行多线程处理会使bool变得易变?

我非常了解volatileC++中的关键字.但在C#中,它似乎采用了不同的含义,与多线程更相关.我认为bool操作是原子的,我认为如果操作是原子的,你就不会有线程问题.我错过了什么?

https://msdn.microsoft.com/en-us/library/x13ttww7.aspx

c# multithreading

6
推荐指数
2
解决办法
434
查看次数

可以(a == 1 && a == 2 && a == 3)在C或C++中评估为true吗?

我们知道它可以用JavaJavaScript.

但问题是,可以在下面的条件永远评估为true 在C或C++?

if(a==1 && a==2 && a==3) 
    printf("SUCCESS");
Run Code Online (Sandbox Code Playgroud)

编辑

如果a整数.

c c++

2
推荐指数
3
解决办法
414
查看次数

编译器如何在 ARM 汇编中强制执行 C++ 易失性

根据 cppreference,一个volatile限定变量的存储不能重新排序为另一个volatile限定变量。换句话说,在下面的示例中,当 y 变为 20 时,可以保证 x 为 10。

volatile int x, y;
...
x = 10;
y = 20;
Run Code Online (Sandbox Code Playgroud)

根据维基百科,ARM 处理器的一个存储可以在另一个存储之后重新排序。因此,在下面的示例中,第二个存储可以在第一个存储之前执行,因为两个目的地是不相交的,因此它们可以自由地重新排序。

str     r1, [r3]
str     r2, [r3, #4]
Run Code Online (Sandbox Code Playgroud)

有了这样的理解,我写了一个玩具程序:

volatile int x, y;

int main() {
    x = 10;
    y = 20;
}
Run Code Online (Sandbox Code Playgroud)

我预计生成的程序集中会出现一些围栏,以保证 x 和 y 的存储顺序。但为 ARM生成的程序集是:

main:
        movw    r3, #:lower16:.LANCHOR0
        movt    r3, #:upper16:.LANCHOR0
        movs    r1, #10
        movs    r2, #20
        movs    r0, #0
        str     r1, [r3]
        str     r2, [r3, #4] …
Run Code Online (Sandbox Code Playgroud)

c++ assembly arm volatile memory-barriers

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