【问题标题】:Can one thread "safely" read from a variable written on by another thread without guards? [duplicate]一个线程可以“安全地”从另一个线程写入的变量中读取,而无需防护? [复制]
【发布时间】:2020-01-12 18:36:54
【问题描述】:

让我安全地定义:不返回乱码。 假设我有一个任何类型的变量;对于这个例子,我使用一个 int 和一个类

class Example
  {
  int a;
  public: 
    void set_int(int b) { a = b; }
    void do_stuff() { std::cout << a << std::endl; }
  }

如果一个线程意外调用 set_int,而另一个线程定期调用 do_stuff(),如果发生冲突,我会简单地打印以控制 a 的旧值(在我的情况下仍然可以),或者我是会在 a 上看到完全不可预测的值吗?

请注意,对我所说的类所做的任何更改都只是一个值重新分配,没有向容器或类似的东西添加元素,不涉及索引或迭代器;只是价值观。

【问题讨论】:

  • 数据竞争表现出未定义的行为。未定义的行为意味着任何事情都可能发生,从“似乎有效”到nasal demons。不要试图推断这个还不错 - 没有 benign data race 这样的东西。说不。
  • @dandan78 出于某种原因,我一直在寻找一个关于没有写入的并发读取的问题,但我找不到你链接的那个。我是否应该将自己的问题标记为重复以帮助将来搜索?

标签: c++ multithreading


【解决方案1】:

一个线程是否可以“安全地”从另一个线程写入的变量中读取而无需保护?

是的,前提是两个操作都相对于彼此进行排序。通常,满足该条件的要求是两个操作都是原子的,并且对于原子类型也满足。非原子类型的读写操作相对于其他线程中的操作是无序的,除非该排序是通过互斥建立的(参见std::mutex)。跨线程的无序操作(其中至少有一个是写入)会导致未定义的行为。

您在示例中使用的int 不保证是 C++ 中的原子类型。 std::atomic 模板的实例保证是原子的——嗯,至少是标准的;如果您定义自定义特化,请确保使用互斥来保持它们的原子性以避免混淆。

【讨论】: