3

I've read about Copy-on-Write concept for optimization in Arrays and other data structures in Swift.

What I want to know is how Copy-on-Write works in a multi-threaded environment.

    let arr1 = [1, 2, 3, 4]
    let arr2 = arr1
    arr1.withUnsafeBytes { print("arr1:", $0.baseAddress) } //0x000060000007ee60
    arr2.withUnsafeBytes { print("arr2:", $0.baseAddress) } //0x000060000007ee60
    
    DispatchQueue.global(qos: .default).async {
        let arr3 = arr1
        arr3.withUnsafeBytes { print("arr3:", $0.baseAddress) } //0x000060000007ee60
    }

In the above code, arr1 and arr2 have same addresses initially as expected in copy-on-write. But, arr3 also shares the same memory as arr1 and arr2 although it is executed on a different thread.

As far as I know, each thread has different stack allocation. Then why arr3 is still sharing the same location?

3
  • 5
    let arr3 = arr1 makes both arrays (initially) share element storage – why should it matter on which thread that code is executed? Btw, the element storage is allocated memory, i.e. on the heap, not on the stack. Commented Jun 19, 2018 at 6:52
  • @MartinR Doesn't element storage depends on what kind of element it is? Commented Jun 19, 2018 at 6:57
  • 2
    I am not sure what you mean and how that is related to the question. Array is a (fixed-sized) struct with a pointer to the (allocated) element storage. – Have a look at mikeash.com/pyblog/… where an Array type with COW is "re-invented," that might give some insights. Commented Jun 19, 2018 at 7:03

1 Answer 1

5

You're not looking at the addresses of the arrays. You're looking at the addresses of the internal backing storage of the arrays, which is shared and heap-allocated.

If you want to look at the addresses of the stack-allocated array container (the part that points to the backing storage), then you meant this:

var arr1 = [1, 2, 3, 4]
var arr2 = arr1
withUnsafePointer(to: &arr1) { print("arr1:", $0) }
withUnsafePointer(to: &arr2) { print("arr2:", $0) }

DispatchQueue.global(qos: .default).async {
    let arr3 = arr1
    withUnsafePointer(to: arr3) { print("arr3:", $0) }
}

// =>
arr1: 0x0000000122d671e0   // local stack
arr2: 0x0000000122d671e8   // local stack (next address)
arr3: 0x0000700000e48d10   // heap

I believe this is the kind of result you were expecting.

Sign up to request clarification or add additional context in comments.

1 Comment

Exactly..:) Thanks a lot.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.