我知道在C中的函数中声明一个静态变量意味着该变量在函数调用之间保留其状态。在线程的上下文中,这是否会导致变量在多个线程上保持其状态,或者在每个线程之间具有单独的状态?
以下是我正在努力回答的过去的纸质考试问题:
以下C函数旨在用于为其呼叫者分配唯一标识符(UID):
get_uid() { static int i = 0; return i++; }
解释get_uid()在多线程调用它的环境中可能以何种方式正常工作。用一个 具体示例场景,详细说明原因和方式 可能会出现不正确的行为。
目前我假设每个线程都有一个单独的变量状态,但我不确定这是否正确,或者答案是否与缺少互斥有关。如果是这种情况,那么在这个例子中如何实现信号量呢?
答案 0 :(得分:17)
您的假设(线程有自己的副本)不正确。代码的主要问题是当多个线程调用该函数get_uid()
时,有一个可能的竞争条件,哪些线程增加i
并获取可能不唯一的ID。
答案 1 :(得分:9)
进程的所有线程共享相同的地址空间。由于i
是静态变量,因此它具有固定地址。它的“状态”只是该地址的内存内容,由所有线程共享。
postfix ++
运算符递增其参数并在递增之前生成参数的值。没有定义完成这些操作的顺序。一种可能的实现方式是
copy i to R1
copy R1 to R2
increment R2
copy R2 to i
return R1
如果正在运行多个线程,它们可以同时执行这些指令或散布。找出各种结果的序列。 (请注意,每个线程都有自己的寄存器状态,即使是在同一CPU上运行的线程,因为在切换线程时会保存并恢复寄存器。)
这种情况根据不同线程中操作的不确定顺序有不同的结果称为竞争条件,因为不同的线程之间存在关于哪一个做什么的“竞争”哪个操作第一。
答案 2 :(得分:3)
不,如果你想要一个变量,哪个值取决于使用它的线程,你应该看一下Thread Local Storage.
一个静态变量,你可以想象它真的像一个完全全局变量。它真的大致相同。所以知道它的地址的整个系统共享它。
编辑:同样注释提醒它,如果将此实现保持为静态变量,竞争条件可能会使值i
同时由多个线程递增,这意味着您不知道函数调用将返回的值。在这种情况下,您应该通过所谓的同步对象保护访问权限,例如mutexes或critical sections。
答案 3 :(得分:1)
由于这看起来像家庭作业,我只会回答其中的一部分,即每个帖子都会共享i
的同一副本。 IOW,线程没有得到自己的副本。我会把互斥的一点留给你。
答案 4 :(得分:1)
每个线程将共享相同的静态变量,该变量很可能是全局变量。某些线程可能具有错误值的情况是竞争条件(增量不是在一次执行中完成,而是在3个汇编指令,加载,增量,存储中完成)。请阅读此处,链接图解释得很清楚。
答案 5 :(得分:1)
如果您使用的是gcc,则可以使用atomic builtin功能。我不确定其他编译器有什么用。
int get_uid()
{
static int i = 0;
return __atomic_fetch_add(&i, 1, __ATOMIC_SEQ_CST);
}
这将确保一次不能通过多个线程对变量执行操作。