c 中的局部静态变量线程如何不安全?

Far*_*uri 5 c static multithreading thread-safety

因此,环顾互联网,我找不到关于此的一致且有用的信息。所以这里的问题是:

为什么说 C 中的局部静态变量是线程不安全的?我的意思是,静态局部变量存储在所有线程共享的数据段中,但是内部链接不应该阻止线程进入彼此的静态变量吗?

这个论坛帖子似乎暗示线程实际上偶尔会介入彼此的数据段,但这种行为是否明显违反了自 90 年代以来的所有 c 标准?如果这种行为是可以预料的,那么在连续的 c 标准中很久以前不赞成使用数据段(即所有具有静态存储持续时间的变量,包括全局变量)吗?

我真的不明白这一点,因为每个人似乎都反对局部静态变量,但人们似乎无法就原因达成一致,研究一些论点表明他们构思不周。

一方面,我认为局部静态变量是在函数调用之间传递信息的一种非常好的方式,它可以真正提高可读性并限制范围(与将信息作为参数传递并在每次函数调用时写回相比) .

据我所知,局部静态变量的使用是完全合法的。但也许我错过了什么?我真的很想知道是不是这样。

[编辑]:这里的答案非常有帮助。感谢大家的洞察力。

Lun*_*din 6

但是内部链接不是应该阻止线程介入彼此的静态变量吗?

不,链接与线程安全无关。它只是限制函数访问在其他作用域中声明的变量,这是一个不同且不相关的问题。

让我们假设你有一个这样的功能:

int do_stuff (void)
{
  static int x=0;
  ...
  return x++;
}
Run Code Online (Sandbox Code Playgroud)

然后这个函数被多个线程调用,线程1和线程2。线程回调函数不能x直接访问,因为它有局部作用域。但是,他们可以呼叫do_stuff()并且可以同时进行。然后你会得到这样的场景:

  • 线程 1 已执行,do_stuff直到返回0调用者为止。
  • 线程1即将写入值1x,但在此之前它..:
  • 上下文切换,线程 2 步入并执行do_stuff.
  • 线程2读取x,它仍然是0,所以它返回0给调用者,然后增加x1
  • x现在是1
  • 线程 1 再次获得焦点。它即将存储1x所以这就是它的作用。
  • 现在x仍然是1,尽管如果程序运行正确,它应该是2

当访问x在多条指令中完成时,情况变得更糟,因此一个线程读取“一半x”然后被中断。

这是一个“竞争条件”,这里的解决方案是x使用互斥锁或类似的保护机制进行保护。这样做将使函数线程安全。或者,do_stuff可以重写为不使用任何静态存储变量或类似资源 - 然后它会是re-entrant