静态变量和线程(C)

问题描述 投票:0回答:6

我知道在 C 中的函数内声明静态变量意味着该变量在函数调用之间保留其状态。在线程的上下文中,这是否会导致变量在多个线程上保留其状态,或者在每个线程之间具有单独的状态? 这是我正在努力回答的过去的纸质考试问题:

以下 C 函数旨在用于为其调用者分配唯一标识符 (UID):

get_uid() { static int i = 0; return i++; }

解释 get_uid() 在多线程调用的环境中可能会以何种方式错误地工作。使用
  具体的示例场景,给出关于原因和方式的具体细节
  可能会出现不正确的行为。

目前我假设每个线程都有一个单独的变量状态,但我不确定这是否正确,或者答案是否更多地与缺乏互斥有关。如果是这样的话,那么在这个例子中如何实现信号量呢?

c multithreading concurrency static mutual-exclusion
6个回答
26
投票
get_uid()

,可能存在

竞争条件
,哪些线程会递增i并获取可能不唯一的ID。
    


18
投票
i

是静态变量,因此它有固定的地址。它的“状态”只是该地址处的内存内容,由所有线程共享。


后缀

++

运算符递增其参数并生成递增之前的参数值。这些操作的完成顺序没有定义。一种可能的实现是


copy i to R1 copy R1 to R2 increment R2 copy R2 to i return R1

如果有多个线程正在运行,它们可以同时或分散执行这些指令。自己计算出可以获得不同结果的序列。 (请注意,每个线程确实有自己的寄存器状态,即使对于在同一 CPU 上运行的线程也是如此,因为当线程切换时会保存和恢复寄存器。)

这种根据不同线程中不确定的操作顺序而产生不同结果的情况称为“竞争条件”,因为不同线程之间存在“竞争”,即哪个线程先执行哪个操作。

不,如果您想要一个值取决于使用它的线程的变量,您应该看看

线程本地存储。

5
投票

静态变量,你可以想象它真的像一个完全的全局变量。真的很相似。因此它由知道其地址的整个系统共享。

编辑

:同样作为注释提醒它,如果您将此实现保留为静态变量,竞争条件可能会使值

i

同时由多个线程递增,这意味着您没有任何函数调用将返回的值的想法。在这种情况下,您应该通过所谓的同步对象(如互斥体

临界区
)来保护访问。 由于这看起来像家庭作业,我将仅回答其中的一部分,即每个线程将共享

i

1
投票

如果您使用 gcc,则可以使用 

atomic 内置

1
投票

int get_uid() { static int i = 0; return __atomic_fetch_add(&i, 1, __ATOMIC_SEQ_CST); } 这将确保该变量不能同时被多个线程操作。


每个线程将共享相同的静态变量,该变量很可能是全局变量。某些线程可能具有错误值的情况是竞争条件(增量不是在一次执行中完成的,而是在 3 个汇编指令中完成的:加载、增量、存储)。阅读此处,链接中的图表很好地解释了这一点。


1
投票

© www.soinside.com 2019 - 2024. All rights reserved.