• Swift全局变量的线程安全分析


    一、示例代码

    import UIKit
    
    let obj = TestObj()
    
    class TestObj {
        init() {
            print("(type(of: self)) init")
        }
    }
    
    class ViewController: UIViewController {
        
        func test() {
            let x = obj
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            print("ViewController start view didload")
            DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                for _ in 0...100000 {
                    DispatchQueue.global().async {
                        let x = obj
                        print(x)
                    }
                }
            }
        }
    }
    

     问题,TestObj 中的初始化方法何时调用?

    二、经过测试

      方法在 viewDidLoad 的 log “ViewController start view didload”输出5s之后才会调用

      因为swift中static修饰的全局变量或者类变量都是lazy load,也就是第一次使用的时候才会初始化,并且这个初始化过程是原子化的 

    三、多线程安全分析 

      结论: 

        对于只读的全局变量,在多线程环境下面读是安全的;

        对于可变的全局变量,多线程下面写是不安全的,可能造成引用计数不正确,错误释放。

        具体可参考:

        https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html

      为什么只读的情况下面多线程访问是安全的,可以看下面的方法

      

     这个方法的反汇编(DEBUG模式下面,编译器优化之后可能有变化)

    int _$s14GlobalVarTest214ViewControllerC4testyyF() {
        rax = GlobalVarTest2.obj.unsafeMutableAddressor : GlobalVarTest2.TestObj();
        rax = *rax;
        var_18 = rax;
        swift_retain(rax);
        rax = swift_release(var_18);
        return rax;
    }

    可以看到全局变量在这个作用域内是先进行了retain操作,最后进行了release。

    对一个对象的retain和release操作,本身这个方法是原子操作的,所以不用担心这两个方法的线程安全问题。

    如果是全局可写的变量,当两个线程对这个对象进行改变的时候

    retain和release中间会出现穿插,导致业务上引用计数的变化不再安全。

    因此,对于全局变量写操作,必须进行加锁,保证retain和release在正确的逻辑中。

      

  • 相关阅读:
    Decimal 格式化输出( 去掉多余的0和点)
    HTML Character Sets
    生成下面的模块时,启用了优化或没有调试信息
    PJBLog的CSS模板图
    .NET 实例化顺序
    Live Mail 报错 0x80048820 可能的处理方式
    Windows下将Ldif文件导入OpenLdap时的中文转换问题
    DataGrid中动态添加列
    Sip协议栈消息层的设计与实现
    Prism学习笔记模块之间通信的几种方式
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/15049161.html
Copyright © 2020-2023  润新知