gpt4 book ai didi

c++ - 整数读取需要临界区保护吗?

转载 作者:可可西里 更新时间:2023-11-01 16:29:19 25 4
gpt4 key购买 nike

我遇到过 C++03 中一些采用这种形式的代码:

struct Foo {
int a;
int b;
CRITICAL_SECTION cs;
}

// DoFoo::Foo foo_;

void DoFoo::Foolish()
{
if( foo_.a == 4 )
{
PerformSomeTask();

EnterCriticalSection(&foo_.cs);
foo_.b = 7;
LeaveCriticalSection(&foo_.cs);
}
}

foo_.a 的读取是否需要保护?例如:

void DoFoo::Foolish()
{
EnterCriticalSection(&foo_.cs);
int a = foo_.a;
LeaveCriticalSection(&foo_.cs);

if( a == 4 )
{
PerformSomeTask();

EnterCriticalSection(&foo_.cs);
foo_.b = 7;
LeaveCriticalSection(&foo_.cs);
}
}

如果是,为什么?

请假设整数是 32 位对齐的。平台是 ARM。

最佳答案

技术上是的,但在许多平台上都不是。首先,让我们假设 int 是 32 位(这很常见,但不是通用的)。

32 位 int 的两个字(16 位部分)可能会被单独读取或写入。在某些系统上,如果 int 未正确对齐,它们将被单独读取。

想象一个系统,您只能进行 32 位对齐的 32 位读取和写入(以及 16 位对齐的 16 位读取和写入),以及一个跨越这种边界的 intint 最初为零(即 0x00000000)

一个线程将 0xBAADF00D 写入 int,另一个“同时”读取它。

写入线程首先将0xBAAD写入int的高位字。然后读取器线程读取整个 int(包括高位和低位),得到 0xBAAD0000 —— 这是 int 从未进入的状态故意的!

写入器线程然后写入低位字 0xF00D

如前所述,在某些平台上,所有 32 位读/写都是原子的,因此这不是问题。然而,还有其他问题。

大多数锁定/解锁代码都包含对编译器的指令,以防止跨锁重新排序。如果没有防止重新排序,编译器可以自由地重新排序,只要它在单线程上下文中表现得“好像”它会那样工作。因此,如果您在代码中读取 a,然后读取 b,编译器可以在读取 a 之前读取 b,如此长因为它没有看到在该时间间隔内修改 b 的线程内机会。

因此,您正在阅读的代码可能正在使用这些锁来确保变量的读取按照代码中写入的顺序进行。

其他问题在下面的评论中提出,但我觉得没有能力解决它们:缓存问题和可见性。

关于c++ - 整数读取需要临界区保护吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13650829/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com