4

如果我像这样在一个线程中更新一个变量:receiveCounter++;

然后从另一个线程我只读取这个变量并将它的值写入GUI。

那安全吗?或者这条指令是否可以在中间被中断,所以当另一个线程读取它时,receiveCounter 中的值是错误的?它一定是正确的,因为 ++ 不是原子的,它是几条指令。

我不关心同步读取和写入,它只需要递增然后在 GUI 中更新,但这不必直接发生在彼此之后。

我关心的是值不能错。就像 ++ 操作在中间被中断,所以读取值完全关闭。

我需要锁定这个变量吗?我真的不想,因为它经常更新。我可以通过将消息发布到主线程并将值复制到队列来解决这个问题(然后需要锁定,但我不会在每次更新时都这样做)我猜。

但无论如何我对上述问题很感兴趣。

4

6 回答 6

3

如果一个线程更改了变量中的值,而另一个线程读取了该值并且程序不同步访问,则它存在数据竞争,并且程序的行为未定义。将类型更改receiveCounterstd::atomic<int>(假设它是一个int开头)

于 2013-08-16T12:04:52.017 回答
2

它的核心是读-修改-写操作,它们不是原子的。周围有一些处理器有专门的指令。像 Intel/AMD 内核一样,很常见,它们有一个 INC 指令。

虽然这听起来可能是原子的,但由于它是一条指令,它仍然不是。x86/x64 指令集与执行引擎的实际实现方式没有太大关系。它执行类似 RISC 的“微操作”,INC 指令被翻译成多个微操作。可以使用指令的 LOCK 前缀使其原子化。但是编译器不会发出它,除非他们知道需要原子更新。

因此,您需要明确说明它。C++11 std::atomic<> 标准添加是一个好方法。您的操作系统或编译器将具有它的内在函数,通常命名为“Interlocked”或“__built_in”。

于 2013-08-16T11:02:37.680 回答
1

简单的回答:不。

因为i++;与 相同i = i + 1;,它包含加载、数学运算和保存值。所以它通常不是原子的。
然而,真正执行的操作取决于 CPU 的指令集,并且可能是原子的,具体取决于 CPU 架构。但默认仍然不是原子的。

于 2013-08-16T08:31:28.667 回答
0

No. Increment operation is not atomic, hence not thread-safe.

In your case it is safe to use this operation if you don't care about its value in specific time (if you only read this variable from another thread and not trying to write to it). It will eventually increment receiveCounter's value, you just don't have any guarantees about operations order.

于 2013-08-16T10:47:16.697 回答
0

一般来说,它不是线程安全的,因为 ++ 运算符包含一个read和一个write,这对不是原子的,可以在两者之间中断。

然后,它可能还取决于语言/编译器/架构,但在典型情况下,增量操作可能不是线程安全的。

(已编辑)

至于读写操作本身,只要你不是64位模式,它们应该是原子的,所以如果你不关心其他线程的值错了1,你的情况可能没问题.

于 2013-08-16T08:32:59.010 回答
0

++ 等价于i=i+1.

++ 不是一个atomic operation所以它的NOT线程安全的。只有基本变量(long 和 double 除外)的读写是原子的,因此是线程安全的。

于 2013-08-16T08:36:15.800 回答