为什么单线程swift会出现内存冲突?

bri*_*efy 2 memory-safety swift

参考官方教程,swift中存在内存冲突,但是,根据我的javascript知识,不存在内存冲突,下面的代码总是正确的。

func balance(_ x: inout Int, _ y: inout Int) {
  let sum = x + y
  x = sum / 2
  y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK
balance(&playerOneScore, &playerOneScore)  // Error: conflicting accesses to playerOneScore
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 5

来自内存安全

\n
\n

具体来说,如果您有两个满足\n以下所有条件的访问,则会发生冲突:

\n
    \n
  • 至少一个是写访问或非原子访问。
  • \n
  • 他们访问内存中的同一位置。
  • \n
  • 它们的持续时间重叠。
  • \n
\n
\n

然后:

\n
\n

函数对其所有输入输出参数具有长期写入访问权限。\n输入输出参数的写入访问在所有\n非输入输出参数求值后开始,并持续\n整个持续时间该函数调用。

\n
\n

因此,将相同的变量作为输入输出参数传递给

\n
func balance(_ x: inout Int, _ y: inout Int) \n
Run Code Online (Sandbox Code Playgroud)\n

算作对同一内存位置的重叠写访问,因此算作冲突。

\n

有关基本原理和更多详细信息,请参阅SE-0176 Enforce Exclusive Access to Memory,它已在 Swift 4 中实现。特别是,强制执行独占内存访问

\n
    \n
  • 防止未定义的行为和意外或令人困惑的结果。
  • \n
  • 允许编译器对加载和存储做出乐观的假设。
  • \n
\n

举个例子,如果将相同的变量作为 inout 参数传递,则以下两个看似等效的函数实际上并不等效,因此变异x会产生影响y,反之亦然:

\n
func balance(_ x: inout Int, _ y: inout Int) {\n    let sum = x + y\n    x = sum / 2\n    y = sum - x\n}\n\nfunc balance(_ x: inout Int, _ y: inout Int) {\n    x = (x + y) / 2\n    y = (x + y) / 2 - x\n}\n
Run Code Online (Sandbox Code Playgroud)\n

另一个例子:

\n
var global = 0\nfunc foo(_ x: inout Int, _ y: inout Int) {\n    x += y\n    global = y\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果变异x可能会修改y,反之亦然,则编译器无法优化代码以y首先将 的值加载到寄存器中,即执行相当于

\n
func foo(_ x: inout Int, _ y: inout Int) {\n    let savedY = y\n    x += savedY\n    global = savedY\n}\n
Run Code Online (Sandbox Code Playgroud)\n

还讨论了(请参阅消除非瞬时访问?)通过在函数调用期间制作临时副本来消除长期访问,这些副本在函数返回时分配回来,即执行类似的操作

\n
func balance(_ x: inout Int, _ y: inout Int) {\n    var (localX, localY) = (x, y)\n    let sum = localX + localY\n    localX = sum / 2\n    localY = sum - localX\n    (x, y) = (localX, localY)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这个想法被放弃了,因为它对性能不利,即使对于 \xe2\x80\x9csimple types\xe2\x80\x9d 来说也是如此,但对于 \xe2\x80\x9ccontainer types\xe2\x80\x9d like 来说更糟糕Array

\n