据我所知,函数调用充当编译器障碍,但不作为CPU障碍.
本教程说明如下:
获取锁意味着获取语义,而释放锁意味着释放语义!其间的所有内存操作都包含在一个漂亮的小屏障三明治中,防止任何不希望的内存重新排序跨越边界.
我假设上面的引用是关于CPU重新排序而不是编译器重新排序.
但我不明白互斥锁和解锁如何导致CPU赋予这些函数获取和释放语义.
例如,如果我们有以下C代码:
pthread_mutex_lock(&lock);
i = 10;
j = 20;
pthread_mutex_unlock(&lock);
Run Code Online (Sandbox Code Playgroud)
上面的C代码被翻译成以下(伪)汇编指令:
push the address of lock into the stack
call pthread_mutex_lock()
mov 10 into i
mov 20 into j
push the address of lock into the stack
call pthread_mutex_unlock()
Run Code Online (Sandbox Code Playgroud)
现在是什么阻止了CPU重新排序mov 10 into i以及mov 20 into j 上方call pthread_mutex_lock()或下方call pthread_mutex_unlock()?
如果它是call阻止CPU进行重新排序的指令,那么为什么我引用的教程使它看起来像是互斥锁和解锁函数来阻止CPU重新排序,为什么我引用的教程没有说任何函数调用会阻止CPU重新排序吗?
我的问题是关于x86架构.
class base
{
public:
virtual void display() = 0;
};
class derived : virtual public base
{
public:
void display()
{
cout << "Display of derived : " << std::endl;
}
};
class derived1 : virtual public base
{
public:
void display()
{
cout << "Display of derived : " << std::endl;
}
};
class derived2 : public derived, derived1
{
};
Run Code Online (Sandbox Code Playgroud)
我将一个纯虚函数放入基类中。我在创建从基类继承的派生类和派生类 1 时使用 virtual 关键字,最后创建了从派生类和派生类 1 继承的派生类 2,然后我会收到错误“派生类:base::void(display) 的继承不明确” “如何解决这个错误?
c++ overriding virtual-functions multiple-inheritance virtual-inheritance
我注意到这可以编译:
#include<memory>
#include<iostream>
using namespace std;
int main()
{
unique_ptr<int>a(nullptr);
if(!a)
cout<<"NULLPTR";
}
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
#include<memory>
#include<iostream>
using namespace std;
int main()
{
unique_ptr<int>a(NULL);
if(!a)
cout<<"NULL";
}
Run Code Online (Sandbox Code Playgroud)
我正在使用具有多个函数的库,这些函数返回原始指针,并且使用后必须手动释放它们。我想使用unique_ptr(带有自定义删除器)来管理这样的原始指针。我担心那些函数返回NULL的情况,因为我认为这可能会引起一些问题。
我在工作项目中发现了一些代码,当子类没有重写基类函数时,该代码会引发错误(实际上,使用此实用程序的基类实际上是抽象的)。当我看到此消息时,我的第一个反应是:“为什么他们不使这些方法成为纯虚拟方法?” 但是,有问题的代码已有15年的历史了,我不确定是否创建该代码是为了填补纯虚拟设备以后会填补的空白(假设当时不存在)。
如果自那时以来存在纯虚拟方法,是否有任何理由为其提供附加或替代功能?(我意识到这可能是主观的,但我什至没有起点)。
如果没有,是否有任何文献指出哪个标准引入了它们?
c++ abstract-class virtual-functions pure-virtual language-lawyer
An std::set是一种分类的关联容器,可快速查找其元素。密钥以一种有序的方式插入,一旦插入就不能修改密钥以保持该顺序。
考虑下面的示例,该示例构造一个std::set,int*然后尝试破坏其元素的排序:
#include <iostream>
#include <set>
int values[] = { 50, 40, 30, 20, 10 };
// Comparator that sorts by pointed value
struct comparator {
bool operator()(const int* left, const int* right) const {
return *left < *right;
}
};
using my_set_t = std::set<int*, comparator>;
// Checks if each of the elements of `values` are in the set
void output(const my_set_t & foo)
{
for (auto & x : values) {
std::cout << …Run Code Online (Sandbox Code Playgroud) 我不知道为什么我的代码不是线程安全的,因为它输出了一些不一致的结果。
value 48
value 49
value 50
value 54
value 51
value 52
value 53
Run Code Online (Sandbox Code Playgroud)
我对原子对象的理解是,它防止其中间状态暴露出来,因此当一个线程正在读取它而另一线程正在写入它时,它应该解决该问题。
我曾经认为我可以使用没有互斥量的std :: atomic来解决多线程计数器增量问题,但情况并非如此。
我可能误解了原子对象是什么,有人可以解释吗?
value 48
value 49
value 50
value 54
value 51
value 52
value 53
Run Code Online (Sandbox Code Playgroud) C++20 包括atomic<float>和的专门化atomic<double>。这里有人能解释一下这有什么实际用途吗?我能想象的唯一目的是,当我有一个线程在随机点异步更改原子双精度或浮点并且其他线程异步读取该值时(但易失性双精度或浮点实际上应该在大多数平台上执行相同的操作)。但这种需要应该是极其罕见的。我认为这种罕见的情况不能证明纳入 C++20 标准是合理的。
这可能是一个与语言无关的问题,但实际上我对 C++ 的情况感兴趣:如何用支持 MT 编程的 C++ 版本编写多线程程序,即具有内存模型的现代 C++,如何证明是正确的?
在旧的 C++ 中,MT 程序只是根据 pthread 语义编写,并根据 pthread 规则进行验证,这在概念上很简单:正确使用原语并避免数据竞争。
现在,C++ 语言语义是根据内存模型定义的,而不是根据原始步骤的顺序执行来定义的。(该标准还提到了“抽象机器”,但我不再明白它的含义。)
如何用非顺序语义证明 C++ 程序的正确性?一个程序没有一个接一个地执行原始步骤,怎么能推理出这个程序呢?
C++(草案)标准包含我所说的“ROMability 条款”,即[basic.life]/10:
在具有静态、线程或自动存储持续时间的 const 完整对象占用的存储中,或在此类 const 对象在其生命周期结束之前曾经占用的存储中创建新对象,将导致未定义的行为。
第一部分很好:“静态,线程”“存储持续时间”。允许重复使用这种存储是不合理的。
但是最后一部分呢:
自动存储持续时间占用,或在此类 const 对象在其生命周期结束之前曾经占用的存储空间内
这是否意味着用户需要避免在堆栈可能已使用的任何内存位置创建任何对象(用于存储自动对象)?
这将阻止在自动对象的任何子对象上使用新放置,或使用执行此类操作的库工具。
这是零意义的,但在我看来,它确实是这里指定的内容。
我想Base从班级本身之外以不合格的方式(为什么?宏魔法)访问班级成员。策略是在Derived类中执行并将指向指针转换Base为指向指针Derived(即使实例不是a Derived)。
就我尝试而言,代码编译并正确运行:这是标准还是意外(标准是UB)?链接
#include<iostream>
struct Base{
int a=3;
};
struct Derived: public Base{
int getA(){
// this scope has unqualified access to Base class members
return a;
}
};
int main(void){
Base b;
std::cerr<<((Derived*)(&b))->getA()<<std::endl;
}
Run Code Online (Sandbox Code Playgroud) c++ ×9
memory-model ×2
stdatomic ×2
assembly ×1
atomic ×1
c ×1
c++14 ×1
casting ×1
constants ×1
downcast ×1
inheritance ×1
invariants ×1
mutex ×1
overriding ×1
pointers ×1
pure-virtual ×1
std ×1
stdset ×1
unique-ptr ×1
x86 ×1