[swift-dev] Thread safety of weak properties
kevin at sb.org
Sat Dec 12 02:01:09 CST 2015
On Fri, Dec 11, 2015, at 07:00 AM, Mike Ash via swift-dev wrote:
> Increasing the inline size of weak references opens up the possibilities a bit. I can think of at least four fixes:
> 1. Delete the zeroing, and otherwise leave things as-is. This extends the life of the object husk (by the way, is there an official term?) possibly indefinitely. This seems fine to me but it sounds like you may disagree. I will, of course, defer to your judgment on that.
I don't mind un-zeroed weak references keeping an object husk around, but if I read a weak reference and get nil back, I expect the reference to now be zeroed and to not prolong the lifetime of the husk. It's probably not that big a deal, but it would be surprising if it behaved differently.
I think swift_weakCopyInit() and swift_weakTakeInit() have to also be updated for whatever change is done to swift_weakLoadStrong() as those two functions are conceptually just reads of the src pointer, but like swift_weakLoadStrong() they zero out and release the object if it's deallocating.
Another possible fix is to just atomically load/store the Value pointer itself (assuming all platforms Swift runs on supports lock-free atomic pointers). This way if the object is deallocating, it would attempt an atomic CAS on the pointer to null it out, and only release the object if it wasn't already null. This means all writes to weak pointers now require an atomic write, but the benefit over the activity count / spinlock is reads don't have to perform an atomic write while the object is still alive, only an atomic read (although I'm not sure offhand if there's any practical performance difference there). And with this approach, it now becomes easy to make read/write and write/write safe. Whether this approach is worth doing depends on how many weak writes there are compared to weak reads (and offhand I don't have any idea there, except I do know I see an awful lot of code that looks like `weakRef?.foo(); weakRef?.bar(); weakRef?.baz()`).
More information about the swift-dev