RFC: Shared Thread Safe References #76
Replies: 2 comments 5 replies
-
I'd say that making references work with threads is non-negotiable. An Consider libraries which use a Multi-threaded programs do often offer performance advantages, while programs that don't run offer very little performance indeed. |
Beta Was this translation helpful? Give feedback.
-
The cost of atomics IMO is too large for our case of ref-counting. At least in Python they found out that switching over degrades performance by 23%. I believe there are systems that opted for a tracing GC because it is cheaper than atomics everywhere. So I think to effectively implement this, we need to either:
|
Beta Was this translation helpful? Give feedback.
-
Issue
Concurrently allocating memory to ref objects while consuming (decrementing) the ref count in other threads in parallel results in undefined behaviour which causes SIGSEGVs. This is especially apparent in higher thread counts where the likelihood of this occurring increases dramatically (anything more than 2 threads on naive tests starts to hit SIGSEGVs pretty regularly).
Example
This issue is apparent on loony and was delved into further with evilcanary.
Source of SIGSEGV
Naturally, it came down to incref, decref and islastdecref not being atomic. Memory thread fences only applied a level of temporal coherency that did not apply to any changes to volatile memory after the elements were removed from the queue. While the allocator uses locks, this doesnt prevent dirty memory being accessed too soon by the allocating thread which can result in a SIGSEGV in the allocator algorithm.
Solution
After fiddling with the system arc file, I found that introducing atomic operations to the 3 key operations listed above completely absolved my tests of any undefined behaviour. These should/can be implemented through:
Shared Ref
A simple solution (but also the most annoying for it having to introduce another annoying keyword) is to create a new
shared ref
type that might be represented bysref
( or something that looks less like shrek) and enforcing atomic operations.Ref modification
Alternatively, we can simply use
when hasThreadSupport
expressions to change ref counting to use atomic operations.Costs
Atomic writes have a significantly larger cost than loads. Because of the extra cost, I would like to minimize the use of Atomic operations wherever possible, therefore I prefer the first solution over the second.
But can't you just make a library that implements something like this?
Yes? But also the default
ref
"traced pointer" should do what's written on the label imo. Or developers should be provided with more primitives such as hooks to modify how their objects reference headers are interacted with.Beta Was this translation helpful? Give feedback.
All reactions