我们为什么不正常地使类线程的每个属性安全?

时间:2019-11-20 18:55:01

标签: ios swift multithreading thread-safety

我正在阅读有关iOS中线程安全属性的信息。我遇到的一个问题:

这个问题不是关于如何实现线程安全属性,而是为什么和为什么不这样做。

为什么我们不正常地使类线程的每个属性安全,以免我们不必担心线程安全? 使类线程的每个属性安全都是好事,还是会影响应用程序性能,所以不是一个好主意,除非明确要求?

2 个答案:

答案 0 :(得分:4)

这是一个很好的问题。我认为有两个主要原因。

首先,我们可以默认使每个属性都是原子的,而对于Objective-C @property来说确实如此。但是,如果您阅读了大多数Objective-C,则大多数@property声明都会显式覆盖默认值,并使属性为nonatomic。将属性设置为原子,会增加访问该属性的开销,但可能会带来很小的潜在开销,这会影响性能。大多数属性不需要 是原子的,因此可以通过使它们成为nonatomic来避免性能下降。在Swift中,默认情况下属性是非原子的,并且没有内置的方法可以使它们成为非原子的。

第二个是使每个属性“线程安全”(我假设您是原子的),不能确保整个类/结构都是线程安全的,并且肯定不会使更高级别的构造线程安全。线程安全是一个复杂的问题,不能仅在单个属性的级别上解决。如果该语言声称默认情况下属性是线程安全的,那么这可能会使开发人员(尤其是较新的开发人员)陷入一种错误的安全感,从而使他们更有可能假设他们不必担心线程安全和编写有问题的多线程代码结果是。

相反,属性级原子性只是编写有效,高性能,正确的多线程API所需的大型工具箱中的一种工具。苹果公司(IMO)正确地认为,程序员应该真正理解他们试图解决的整个问题,并使用自己的代码来解决它。

(这并不排除以后对Swift的改进,这些改进确实使安全的多线程变得更容易。可以做很多事情,并且希望可以做很多事情,使多线程更容易。)

答案 1 :(得分:2)

“线程安全性”所隐含的最重要的要求之一是确保对某些共享数据进行操作的一个线程的操作绝不会导致其他线程在不一致或无效的状态下看到相同的数据。

但是,“不一致或无效”是什么意思?只有应用程序开发人员可以肯定地说。通常,它与单个对象的不同属性之间和/或不同对象之间的关系之间的关系有关。

@Andrew Madsen建议使单个属性“原子化”可能还不够。这就是为什么不这样:

假设线程A必须更改三个不同的属性p1,p2和p3,以完成其工作;并假设线程B需要查看那些相同的属性。将单个属性设置为“原子”可确保在查看任何给定属性时,确保线程B看到“之前”值或“之后”值。它将再也看不到任何其他值。

但这可能不足以确保线程安全。如果线程B看到p1的“之前”值,但看到p2和p3的“之后”值,会发生什么呢?在某些程序中,这可能导致线程B计算错误的结果,存储错误的数据,甚至使程序崩溃。

需要“原子”的是线程A执行的整个操作。我们需要确保线程B要么看到所有三个属性的“ before”值,要么看到所有三个属性的“ before”值,

我们通过确保线程A除非锁定了某个互斥锁,才执行其工作来实现该保证,并且还必须确保线程B除非已经锁定了线程A,否则绝不会查看这些属性。 相同的互斥锁