提问人:mouse_00 提问时间:7/27/2023 最后编辑:mouse_00 更新时间:7/27/2023 访问量:124
通过引用传递值是线程安全的吗?
Is passing value by reference thread-safe?
问:
我有以下代码:
#include <thread>
void foo(int& value)
{
// do nothing
}
int main()
{
int value = 42;
std::thread t1([&value]{ foo(value); });
std::thread t2([&value]{ value = 100500; });
t1.join();
t2.join();
return 0;
}
常识告诉我们这里没有数据竞争,因为通过引用传递值“必须”(???) 是线程安全的,但我无法根据 cppreference 或标准草案 N4950 对其进行验证。
- 如何验证没有基于 cppreference 或标准的数据争用?
- 通过引用传递值是线程安全操作吗?
答:
1赞
Yakk - Adam Nevraumont
7/27/2023
#1
在没有排序之前/之后关系的情况下修改或读取相同的值是一种争用条件。(实际规则更复杂,但这足以避免竞争条件,并且在违反此规则的同时避免竞争条件非常具有挑战性)。
传递引用不会修改或读取某些内容。
因此,从狭义上讲,您的代码没有争用条件,因为两个线程中只有 1 个会读取或写入您的变量。在创建修改它的变量之前修改该变量具有 happens-before 关系。std::thread
但是,如果对其参数执行任何非平凡操作,则代码会突然表现出未定义的行为。foo
评论
0赞
mouse_00
7/27/2023
你说“传递参考文献不会读到一些东西”,但我在 cpprenot 中找不到这些信息。您能提供一些参考吗?
0赞
paddy
7/27/2023
你读过参考声明吗?也许你要找的是:“引用,一旦初始化,总是引用有效的对象或函数”。
0赞
mouse_00
7/27/2023
@paddy,它并没有真正说明“引用初始化”是“读取操作”或“线程安全”
0赞
paddy
7/27/2023
您担心的“线程安全”问题究竟是什么?标识符是执行 的线程拥有的整数。对该数据的所有引用也由此线程创建。任何线程上引用的任何可能的“副本”也将引用同一对象。该对象在一个线程中存在一次,并且对它的所有引用都是不可变的。value
main
0赞
Chris Dodd
7/27/2023
@mouse_00:关键是引用初始化不是对引用要初始化以引用的对象的读取操作。因此,在代码中,它永远不会实际访问 的值(它只创建对它的引用),因此不会有竞争。t1
value
评论
foo
foo
value
value
t2
main
value
const
value
mutex