Preface
As we all know, Swift is a type-safe language that prevents unsafe behavior in your code by reporting an error by the compiler. For example, variables must be declared before use, memory cannot be accessed after variables are destroyed, and arrays are out of bounds.
Swift will ensure that your code does not have memory access conflicts by modifying the same piece of memory at the same time in a mutually exclusive access right (at the same time, there can only be one write permission). While Swift manages memory automatically, in most cases you don't need to care about this. However, it is also very necessary to understand under which circumstances memory access conflicts will occur.
First, let’s take a look at what memory access conflict is.
Memory access violation
When you set values or read variables worth it, you will access memory.
var age = 10 // Write permissionprint(age) // Read permission
When we read and write operations on the same piece of memory at the same time, unpredictable errors will occur. For example, if there is another code that sets it to 20 during the period when you read its value, then what you read may be 10 or 20. This creates problems.
Memory access conflict: When reading and writing operations are performed on the same piece of memory at the same time, or multiple write operations are performed at the same time, memory access conflicts will occur.
After understanding what memory access conflict is, let’s see what situations will cause memory access conflicts.
In-Out Parameters
When the In-Out parameter is a global variable and the variable is modified in the function body, a memory access conflict will occur. For example, the following code:
var age = 10 func increment(_ num: inout Int) { // step1 num += age // step2 } increment(&age)
increment(:) In the entire function body, all In-Out parameters have write permissions. In the above code, step1 has obtained write permissions for age, while step2 has obtained read permissions for age, which results in the same piece of memory and read and write operations at the same time. This causes memory access conflicts.
The above problem can be solved by copying age:
// step1 var copyOfAge = age increment(©OfAge) age = copyOfAge
step1 copies the value of age to another piece of memory, so that there are read permissions to age and write permissions to copyOfAge in the function body. Because age and copyOfAge are two pieces of memory, there will be no memory access conflicts.
mutating function of structure
For the mutating function of a structure, its entire function body has self write permission.
struct Person { var age: Int mutating func increment(_ num: inout Int) { age += num } } var p1 = Person(age: 10) (&)
The above code compiler will report an error:Overlapping accesses to 'p1', but modification requires exclusive access; consider copying to a local variable
. It's obviously a memory access conflict.
The In-Out parameter obtains write permissions to p1; the mutating function also obtains write permissions to p1. There are two write operations in the same memory. Causes memory access conflicts. It can be solved by copying operations as above.
Properties of value type
For value types such as structures, enums, ancestors, etc., modifying their properties is equivalent to modifying their entire values. For example, the following code:
func increment(_ num1: inout Int, _ num2: inout Int) { print(num1 + num2) } var tuple = (age: 10, height: 20) increment(&, &)
& got the write permission of tuple, & got the write permission of tuple again. There are two write operations in the same memory. Causes memory access conflicts.
This problem can be solved by local variables:
func someFunction() { var tuple = (age: 10, height: 20) increment(&, &) }
Because in the someFunction() function, age and height do not generate any interaction (age and height are not read or written during it), the compiler can ensure memory security.
PS: Regarding the question in the comment area, what does it mean to have no interaction in the someFunction() function?
Answer: In someFunction(), the compiler can ensure that there are no other threads to read or modify the tuple. Therefore, memory security can be ensured. For global variables, the compiler cannot guarantee whether other threads are reading or modifying them.
The following code is code that interacts in the function body. Although it is a local variable, it involves multiple threads modifying the value of the tuple, which will cause memory access conflicts:
func someFunction() { var tuple = (age: 10, height: 20) { += 10 } { increment(&, &) } }
Summarize
When reading and writing operations are performed on the same piece of memory at the same time, or multiple write operations are performed at the same time, memory access conflicts will occur.
This will cause memory access violations:
- In-Out is a global parameter and it is modified within the function body.
- Modify the value of the structure in the mutating function of the structure.
- Multiple attributes of the same value type are used as In-Out parameters of the function.
This is the end of this article about what situations Swift will encounter memory access conflicts. For more related contents of Swift memory access conflicts, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!