【问题标题】:Does the following situations create race conditions in multithreading?以下情况是否会在多线程中产生竞争条件?
【发布时间】:2020-12-15 11:35:04
【问题描述】:

我是 C++ 多线程的新手(显然它与 python 多线程/多处理不同,因为多个线程可以在单个进程中使用多个 CPU)。我知道如果 2 个线程尝试同时更改相同的数据,或者如果一个线程读取某些内容而另一个线程正在更改它,则会发生竞争条件,但我不确定以下情况是否需要同步:

假设我有以下课程:

class Animal{
public:
    string name_;
    Animal(string name);
    ~Animal();
};

class Dog : public Animal{
public:
    int price_;
    Dog(string name, int price);
    ~Dog();
};

class Cat : public Animal{
public:
    int price_;
    Cat(string name, int price);
    ~Cat();
};

void do_stuff(){
    Animal* a = new Dog("Foo", 3);
}

是否安全:

  1. 让一个线程执行 static_cast 或 dynamic_cast 而另一个线程正在读取或写入对象?
// thread 1
a->name = "Bar";
// thread 2
Dog* d = static_cast<Dog*>(a);
  1. 有一个线程读取对象的属性,而另一个线程正在写入同一对象的另一个属性?根据这篇文章 (Accessing different data members belonging to the same object from 2 different thread in C++) 似乎没问题,但显然它会导致缓存问题?

谢谢

【问题讨论】:

  • (1) static_cast 甚至根本不访问对象 - 只是指针。 (2) 你看答案了吗?
  • 谢谢!是的,我阅读了答案,发现它会使事情变慢,但我不完全理解数据成员对齐的含义
  • 对齐 - CPU 和内存没有类型的概念。整数是一种语言结构。编译器为 int 保留 4 个字节。如果这 4 个字节跨越一个高速缓存行,则可能需要 2 个 CPU 指令来完成它(即它不是原子的)。但是,编译器通常在 4 字节/8 字节边界上对齐类型。主流 CPU 加载和存储操作在字大小的字对齐位置上是原子的。位域是指不同的变量具有奇怪的大小并共享相同的字节。 (例如:A 是 17 位,B 是 15 位。两者都存储在一个 4 字节块中)。
  • 虚假共享 - 今天的缓存行是 64 字节。写入高速缓存行的不同字是原子的,但会导致多个 CPU 之间的高速缓存争用。根据定义,这不是数据竞争,而是由于缓存利用率而导致性能不佳。

标签: c++ multithreading inheritance caching casting


【解决方案1】:

不要去那里。

如果存在仅由一个线程写入/读取的数据,则根据定义,它不是共享数据,也不需要是全局数据。

如果有数据由一个线程写入并最终由另一个线程读取,请使用锁、std::atomic 或其他一些 synchronizes-with 关系并收工。

static_castdynamic_cast 和取消引用都是读取。

  1. 不应该是一场比赛。

  2. 只要对齐没问题并且成员不是位域,就不应该是比赛。

但最重要的是,在现代 C++ 中,您必须使用 synchronizes-with 关系或明确告诉编译器某些数据是通过 std::atomic 共享的。在任何多线程程序中,甚至在玩具示例中,都会出现一个线程读取另一个线程编写的内容的点。此时,需要同步。

【讨论】:

    猜你喜欢
    • 2021-08-27
    • 2018-07-05
    • 1970-01-01
    • 2020-08-25
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多