为什么对象的可变性与其Thread安全性相关?

时间:2015-02-03 04:21:38

标签: ios multithreading

我正在使用IOS上的CoreImage,你们知道CIContext和CIImage是不可变的,所以它们可以在线程上共享。问题是我不确定为什么对象'可变性与其线程安全密切相关。

我可以猜测粗略的原因是为了防止多个线程同时对某个对象做某事。但任何人都可以提供一些理论证据或给出具体答案吗?

3 个答案:

答案 0 :(得分:2)

嗯,实际上,你是对的。

如果你有一个不可变对象,你所能做的就是从中读取数据。并且每个线程都将获得相同的数据,因为该对象无法更改。

当你有一个可变对象时,问题是(通常)读写操作不是原子的。这意味着它们不是即时执行的,它们需要时间。所以它们可以相互重叠。即使我们有单核处理器,它也可以在任意时刻在线程之间切换。可能导致的问题:

1)两个线程同时写入同一个对象。在这种情况下,对象可能会损坏(例如,一半数据来自第一个线程,另一半来自第二个,结果是不可预测的。

2)一个线程写入数据,另一个线程读取它。一个问题是线程可能读取已经过时的数据。另一个是它可能会读取损坏的数据(如果写入线程尚未完成写入)。

答案 1 :(得分:2)

你是对的,可变对象不是线程安全的,因为多个线程可以同时写入该数据。这与读取数据相反,多个线程的操作可以同时进行而不会引起问题。只能读取不可变类型。

但是,当多个线程写入相同的数据时,这些操作可能会发生干扰。例如,两个线程正在编辑的NSMutableArray很容易被破坏。一个线程在一个位置编辑,突然改变另一个线程正在更新的内存。 iOS将对简单数据类型使用所谓的原子操作。这意味着iOS要求编辑操作在其他任何事情发生之前完全完成。这比锁具有效率优势。如果您想了解更多内容,请关注Google。

答案 2 :(得分:1)

以一组值为例。假设我正在做一些计算,我发现数组的计数为4

var array = [1,2,3,4]
let count = array.count

现在也许我想循环遍历数组中的所有元素,所以我设置了一个循环,它通过索引i< 4或沿着这些行的东西。到目前为止一切都很好。

这个数组是可变的,所以在一个单独的线程上,我可以轻松地删除一个元素。所以也许我在线程1上,我得到的计数是4,我可能开始循环遍历数组。现在我们切换到线程2并删除一个元素,所以现在这个相同的数组中只有3个值。如果我最终回到线程1并且我仍然假设我在循环数组时有4个值,那么当我尝试访问第4个元素时,我的程序会崩溃。

这就是为什么不可变性,它可以保证跨线程的某种程度的一致性。