繁体   English   中英

局部静态变量如何在c中不安全?

[英]HOW are local static variables thread unsafe in c?

所以环顾互联网,我无法找到有关这方面的一致和有用的信息。 所以这是问题所在:

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

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

我真的没有得到这个,因为每个人似乎都有一些东西反对局部静态变量,但人们似乎无法就原因达成一致,并且研究一些论证表明它们是错误构思的。

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

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

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

但不是内部联系应该阻止线程踩到彼此的静态变量?

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

让我们假设您有这样的函数:

int do_stuff (void)
{
  static int x=0;
  ...
  return x++;
}

然后这个函数由多个线程,线程1和线程2调用。线程回调函数不能直接访问x ,因为它具有本地范围。 但是,他们可以调用do_stuff() ,他们可以同时执行此操作。 然后你会得到这样的场景:

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

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

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

是不是内部联系应该阻止线程踩到彼此的静态变量?

链接与并发无关:内部链接阻止翻译单元而不是线程看到彼此的变量。

我认为局部静态变量是在函数调用之间传递信息的一种非常好的方法,它可以真正提高可读性并限制范围

通过静态变量在调用之间传递信息与通过全局变量传递信息没有什么不同,原因相同:当你这样做时,你的函数变得不可重入,严重限制了它的用途。

问题的根本原因是具有静态链接的变量的读/写使用将函数形式从无状态转换为有状态。 如果没有静态变量,函数控制的任何状态都必须从外部传递给它; 另一方面,静态变量让函数保持“隐藏”状态。

要查看保持隐藏状态的后果,请考虑strtok函数:您不能同时使用它,因为多个线程会踩到彼此的状态。 此外,如果您希望从当前正在解析的字符串中解析每个标记,则即使从单个线程也无法使用它,因为您的第二级调用会干扰您自己的顶级调用。

从我的角度来看,基础是错误的,或者至少,它与任何其他糟糕的设计一样不安全。

糟糕的软件实践(或线程不安全)可能在没有标准或保护类型的情况下共享资源(如果必须共享资源,则线程之间的通信有不同且很好的方式,例如队列,邮箱等,或信号量和互斥量),但这是开发人员的错,因为他们没有使用正确的机制。

实际上我看不出你的观点,一个静态局部变量,它的范围很好定义(甚至更好,对于嵌入式应用程序有助于避免内存溢出)并且无法访问它,所以我猜不安全代码之间没有关系和静态局部变量(或至少,不是一般意义)。

如果你在谈论一个静态局部变量,它可以从两个不同的任务中写入/读取/没有保护(通过回调或其他),这是一个可怕的设计(再次,开发人员的错),但没有,因为静态局部变量(通常)是不安全的。

在C中,同时读取和写入任何非原子对象的行为未定义

static变量使得这种情况发生的可能性远大于自动或动态变量。 这就是问题的症结所在。

因此,如果您不控制线程(例如使用互斥单元),则可以将程序置于未定义状态。

一种中途宿舍; 某些C编译器可以使用线程本地存储 ,但它尚未被纳入C标准(参见C ++ 11的thread_local )。 例如,请参阅https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Thread-Local.html

是不是内部联系应该阻止线程踩到彼此的静态变量?

你的问题被标记为 C编程语言中没有线程。 如果您的程序创建了任何新线程,它会通过在运行时调用某个库来实现。 C工具链不知道什么是线程,它无法知道你调用的库例程创建线程,并且它无法知道你是否认为任何特定的静态变量被一个或另一个线程“拥有”线。

程序中的每个线程都在与每个其他线程相同的虚拟地址空间中运行。 每个线程可能访问所有可以被任何其他线程可以访问相同的变量。 如果程序中的变量实际上多个线程使用,则程序员有责任(而不是工具链的责任)确保线程以安全的方式使用它。

每个人似乎都有一些针对局部静态变量的东西

团队合作开发大型,长期存在的软件系统的软件开发人员(想想,数十年,数十万到数千万行代码)有一些很好理解的原因可以避免使用静态变量。 不是每个人都在这样的系统上工作,但是你会遇到一些人。

人们似乎无法就原因达成一致

并非所有软件系统都需要维护和升级数十年,而且并非所有系统都有数千万行代码。 这是一个大世界。 出于各种原因,有些人在那里编写代码。 他们并非都有相同的需求。

研究一些论点表明它们是错误的

有些人出于许多不同的原因编写代码......对你来说似乎“错误构思”的东西可能是其他一些开发人员长期以来一直在思考的问题。 也许你并不完全了解他们的需求。

据我所知,本地静态变量有完全合法的用法

是。 这就是他们存在的原因。 与许多其他编程语言一样,C编程语言是一种可以以多种不同方式使用的通用工具。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM