• Understanding Swift’s value type thread safety


    示范代码

    `

    func testScenarioA2() throws {
        var store: Int = 100
        DispatchQueue.concurrentPerform(iterations: 1_000_000) { _ in
            store.negate()
            _ = store
        }
    }
    

    `
    开启线程race诊断后,出现以下错误

    Swift access race in closure #1 (Swift.Int) -> () in UnderstandStruct.testScenarioA2() throws -> ()

    查看汇编
    `
    0x100002a30 <+0>: pushq %rbp
    0x100002a31 <+1>: movq %rsp, %rbp
    0x100002a34 <+4>: subq $0x20, %rsp
    0x100002a38 <+8>: movq 0x8(%rbp), %rdi
    0x100002a3c <+12>: movq %rsi, -0x10(%rbp)
    0x100002a40 <+16>: callq 0x100003bac ; symbol stub for: __tsan_func_entry
    0x100002a45 <+21>: xorl %esi, %esi
    0x100002a47 <+23>: leaq -0x8(%rbp), %rax
    0x100002a4b <+27>: movq %rax, %rdi
    0x100002a4e <+30>: movl $0x8, %edx
    0x100002a53 <+35>: callq 0x100003c06 ; symbol stub for: memset
    0x100002a58 <+40>: xorl %ecx, %ecx
    0x100002a5a <+42>: movl %ecx, %esi
    0x100002a5c <+44>: movq -0x10(%rbp), %rdx
    0x100002a60 <+48>: movq %rdx, -0x8(%rbp)
    -> 0x100002a64 <+52>: movq %rdx, %rdi
    0x100002a67 <+55>: movl $0x1, %edx
    0x100002a6c <+60>: movq %rax, -0x18(%rbp)
    0x100002a70 <+64>: callq 0x100003ba6 ; symbol stub for: __tsan_external_write
    0x100002a75 <+69>: movq -0x10(%rbp), %rax
    0x100002a79 <+73>: movq %rax, %rdi
    0x100002a7c <+76>: callq 0x100003bbe ; symbol stub for: __tsan_read8
    0x100002a81 <+81>: xorl %ecx, %ecx
    0x100002a83 <+83>: movl %ecx, %eax
    0x100002a85 <+85>: movq -0x10(%rbp), %rdx
    0x100002a89 <+89>: subq (%rdx), %rax
    0x100002a8c <+92>: seto %r8b
    0x100002a90 <+96>: testb $0x1, %r8b
    0x100002a94 <+100>: movq %rax, -0x20(%rbp)
    0x100002a98 <+104>: jne 0x100002ac1 ; <+145> [inlined] Swift runtime failure: arithmetic overflow at main.swift:13
    0x100002a9a <+106>: movq -0x10(%rbp), %rdi
    0x100002a9e <+110>: callq 0x100003bc4 ; symbol stub for: __tsan_write8
    0x100002aa3 <+115>: movq -0x10(%rbp), %rax
    0x100002aa7 <+119>: movq -0x20(%rbp), %rcx
    0x100002aab <+123>: movq %rcx, (%rax)
    0x100002aae <+126>: movq %rax, %rdi
    0x100002ab1 <+129>: callq 0x100003bbe ; symbol stub for: __tsan_read8
    0x100002ab6 <+134>: callq 0x100003bb2 ; symbol stub for: __tsan_func_exit
    0x100002abb <+139>: addq $0x20, %rsp
    0x100002abf <+143>: popq %rbp
    0x100002ac0 <+144>: retq
    0x100002ac1 <+145>: ud2
    0x100002ac3 <+147>: nopw %cs:(%rax,%rax)
    0x100002acd <+157>: nopl (%rax)

    `
    0x100002aab <+123>: movq %rcx, (%rax)
    rax是store的地址,直接将计算结果赋给指向的地址。

    结论

    • 对于堆中的变量 store,系统会自动生成 begin_access 和 end_access插桩的检测竞争代码,该代码不影响实际逻辑的执行
    • 对于store的值的改变,不同线程中都是一条mov指令,所以这里存在的线程竞争不会导致crash

    参考
    `

    bb0(%0 : $Int, %1 : $Int):
    debug_value %0 : $Int // id: %2
    debug_value_addr %1 : $
    Int, var, name "store", argno 2 // id: %3
    %4 = begin_access [modify] [unknown] %1 : $Int // users: %7, %6
    // function_ref SignedNumeric.negate()
    %5 = function_ref @$ss13SignedNumericPsE6negateyyF : $@convention(method) <τ_0_0 where τ_0_0 : SignedNumeric> (@inout τ_0_0) -> () // user: %6
    %6 = apply %5(%4) : $@convention(method) <τ_0_0 where τ_0_0 : SignedNumeric> (@inout τ_0_0) -> ()
    end_access %4 : $
    Int // id: %7
    %8 = begin_access [read] [unknown] %1 : $Int // users: %10, %9
    %9 = load [trivial] %8 : $
    Int
    end_access %8 : $*Int // id: %10
    %11 = tuple () // user: %12
    return %11 : $() // id: %12
    }
    `

  • 相关阅读:
    P2788 数学1(math1)- 加减算式
    数据库第三章-学习笔记
    字典序
    P1739 表达式括号匹配
    P3742 umi的函数
    P1765 手机
    P2192 HXY玩卡片
    全排函数c++ next_permutation()
    11.css定义下拉菜单
    10.php引用(&)详解及注意事项
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/14634891.html
Copyright © 2020-2023  润新知