如何定义线程安全?

11

Threadsafe 是一个常出现在文档中的术语,但很少有人解释它的含义,特别是对于初学线程的人来说更难理解。

那么,如何向初学者解释 Threadsafe 代码呢?我目前的想法选项有:

  • 列举使代码线程安全和线程不安全的因素清单
  • 书本定义
  • 一个有用的比喻
8个回答

14

多线程导致执行结果不确定 - 你无法确切知道某个并行代码片段何时运行。

鉴于此,这份精彩的多线程教程线程安全定义如下:

线程安全的代码在任何多线程情况下都没有不确定性。 线程安全主要通过锁定和减少线程之间的交互来实现。

这意味着无论特定的线程如何运行,行为始终是明确定义的(因此不会出现竞态条件)。


13

Eric Lippert说:

当我被问到“这段代码是线程安全的吗?”时,我总是要反问:“你所关心的确切线程情况是什么?”和“在每种情况下对象的正确行为是什么?”。

无法简单地说代码是“线程安全的”,而不传达使用线程安全机制所防止和未防止的不良行为是没有帮助的。


3

你好,

一个不错的起点是阅读POSIX关于线程安全的论文

编辑:只需阅读前几段即可快速了解线程安全和可重入代码。

希望对你有所帮助。

谢谢。


3

我可能有所错误,但线程安全的一个标准是只使用局部变量。如果在不同的线程中调用同一函数时使用全局变量,结果将是不确定的。


只有部分正确,因为你只需要使用互斥锁来保护那些全局变量,就可以拥有一个线程安全的函数。 - claf
@claferri:我认为提问的意图是想知道哪些因素可能导致线程不安全。您肯定可以使用同步对象(不仅仅是互斥量,还有信号量/临界区等)来使事情变得线程安全。我想指出导致线程不安全代码的一件事。这个负评是没有必要的。 - K Singh

2

线程安全的函数/对象(以下简称对象)是一种被设计用于支持多个并发调用的对象。这可以通过对并行请求进行序列化或某种交织调用的支持来实现。

如果该对象能够安全地支持并发请求(来自多个线程),则它是线程安全的。如果它不是线程安全的,则多个并发调用可能会破坏其状态。

考虑一个酒店的日志记录簿。如果一个人正在写入日志,另一个人同时开始写他的信息,最终结果将是两个信息的混合。这也可以通过多个线程写入输出流来演示。


2

0

线程安全的代码是指不会因为同一数据在两个地方同时被修改而导致失败的代码。线程安全是比并发安全更小的概念,因为它假定实际上是同一程序的两个线程进行了操作,而不是硬件修改数据或操作系统。


0

该术语特别有价值的一点是,它位于并发行为的光谱上,其中线程安全是最强的,中断安全比线程安全更弱,而可重入性则更弱。

在线程安全的情况下,这意味着所涉及的代码符合一致的API,并利用资源,以便其他代码在不同线程中(例如其自身的另一个并发实例)不会导致不一致性,只要它也符合相同的使用模式。对于任何合理的线程安全期望,必须指定使用模式。

中断安全约束通常不会出现在现代用户空间代码中,因为操作系统在隐藏此方面方面做得非常好,但在内核模式下这非常重要。这意味着即使在执行过程中触发了中断,代码也将成功完成。

最后一个,可重入性,在所有现代语言中都几乎可以保证,在用户空间内外都是如此,它只是意味着代码段可以被多次输入,即使在旧情况下执行尚未继续执行代码段。例如,在递归函数调用的情况下可能会发生这种情况。通过访问非可重入代码中的共享全局状态变量,很容易违反语言提供的可重入性。


涉及到两个不同的问题——第一个是在执行第一个动作期间是否不能启动嵌套实例,或者它可以在特定允许的点或基本上任意点发生;第二个是嵌套动作是否必须在原始动作恢复之前完成。由于多任务处理非常流行,大多数可以启动嵌套动作的例程将允许它与第一个动作并行运行,但在某些嵌入式环境中仍然普遍存在嵌套动作保存第一个动作上下文的情况... - supercat
1
当它进入时,保存状态,并在退出时恢复。在使用全局状态的情况下,这种模式可能比具有多个活动状态并能够在它们之间切换要容易得多。但是,它对于可以执行的多任务类型施加了一些限制。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接