【问题标题】:What's the proper way to have a Thread-Unsafe object in a singleton?在单例中拥有 Thread-Unsafe 对象的正确方法是什么?
【发布时间】:2016-07-04 07:55:14
【问题描述】:

假设我们有一个 NSMutableArray 例如在一个单例对象上。显然可以从多个不同的线程调用单例对象。

假设我们需要单例用户能够添加或删除对象。或者也许我们有一个需要设置和读取的自定义对象。

处理这些情况的正确方法是什么?如果单例上的每个线程不安全属性都有自己的串行/并发队列,然后覆盖 NSMutableArray 的 addObject 和 removeObject 函数,将读取包装在 dispatch_sync 中,并写入 dispatch_async(到串行队列)或 dispatch_barrier_async(到并发队列)?

1) 每个线程不安全的属性都需要自己的队列吗?或者它至少应该在性能方面有一个。如果多个属性共享同一个队列,它会比必要的慢。

2) 在什么情况下不需要这种线程保护。曾经?或者线程不安全的属性是否应该总是覆盖它们的 setter 和 getter。

【问题讨论】:

    标签: objective-c multithreading cocoa-touch thread-safety


    【解决方案1】:

    1) 每个线程不安全的属性都需要自己的队列吗?或者应该 至少在性能方面有一个。如果多个属性 共享同一个队列,它会比必要的慢。

    完全取决于您使用序列化 API 的频率。从一个简单的模型开始,然后根据需要转向更复杂的模型。

    请记住,实施不一定仅限于随心所欲地添加队列。

    您还可以使用多阅读器、一个编写器模型。这将涉及保留可变数组内容的NSArray* 副本,以便读者可以同时点击。如果可变数组的内容发生了更改,那么您可以(考虑到线程安全)将可变数组的新不可变副本交换为现有的NSArray *(可以使用原子@property 完成,或者您可以使用并发队列所有读取都带有交换操作的屏障)。

    当数组相对较小(廉价副本)或读取次数多于写入次数时,上述方法可能有意义。

    2) 在什么情况下不需要这种线程保护。曾经?要么 线程不安全的属性是否应该总是有它们的 setter 和 getter 覆盖。

    可变集合始终是线程不安全的,即使在“只读”模式下运行也是如此。只有不可变集合是线程安全的。

    所以,是的,您需要确保序列化任何会导致线程不安全操作的操作。

    【讨论】:

    • 谢谢。如果我要为交换操作设置障碍,如果我需要公开访问诸如 removeObject 或 addObject 之类的东西怎么办。最好的做法是为他们编写公共函数,并在他们内部再次阻止他们在并发队列上的操作。
    • @chrisP 你可以结合这两个模型;使用并发队列访问数组的只读副本。然后使用屏障的 addobject/removeobject 操作来改变可变集合制作一个不可变的副本,该副本随后可用于并发读取访问。基于屏障的模型不适用于可变后备存储,因为可变集合在任何角色中都不是线程安全的。
    • 再次感谢。你介意向我解释一下我们评论的最后一行吗? “基于屏障的模型对可变后备存储没有用处,因为可变集合在任何角色中都不是线程安全的。”如果我可以保证我对 NSMutableArray 的所有写入都是对并发队列的 barrier_async,那么我的读者可以不只是__block NSArray *returnArray;dispatch_sync(myConcurrentQueue, ^ { returnArray = [myMutableArray copy]; });return returnArray;。这行不通吗?或者它仍然可以工作,但不如您提到的附加 NSArray 有效。
    • 如果这仍然有效,但效率不高,您是否介意解释一下。谢谢!
    • ...等。如果有人将障碍异步切换为非障碍,或者任何人添加了一些没有障碍的可变访问器,我们就会发现自己处于可怕的境地。所以我会确保永远不会这样做。我只是从假设的角度感兴趣“IFF所有对可变集合的写入/访问器都是屏障异步,从技术上讲,您可以使用dispatch_sync可变集合中的副本安全。”即使它不是线程安全的函数,因为我们可以保证在这种情况下一切都是障碍,我们不会遇到任何问题。真是愚蠢的问题,但请幽默:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2010-10-03
    • 2020-06-15
    相关资源
    最近更新 更多