3 ms·
atomics aren't free even without contention. the slogan of the language is "you don't pay for what you don't use", and it's really not great that there's no no
by izabera 1y ago
atomics aren't free even without contention. the slogan of the language is "you don't pay for what you don't use", and it's really not great that there's no non atomic refcount in the standard. the fact that it is default atomic has also lead people to assume guarantees that it doesn't provide, which was trivially predictable when the standard first introduced it.
- eMSF 1y agoRelated to this, GNU's libstdc++ shared_ptr implementation actually opts not to use atomic arithmetic when it infers that the program is not using threads.
- menaerus 1y agoI never heard of this and went to check in the source and it really does exist: https://codebrowser.dev/llvm/include/c++/11/ext/concurrence.h.html#__gnu_cxx::__default_lock_policy https://codebrowser.dev/llvm/include/c++/11/ext/concurrence....
- aw1621107 1y agoThe code you linked is a compile-time configuration option, which doesn't quite match "infer" IMO. I think GP is thinking of the way that libstdc++ basically relies on the linker to tell it whether libpthread is linked in and skips atomic operations if it isn't [0]. [0]: https://snf.github.io/2019/02/13/shared-ptr-optimization/ https://snf.github.io/2019/02/13/shared-ptr-optimization/
- menaerus 1y agoIt's a compile-time flag which is defined when libpthread is linked into the binary.
- aw1621107 1y agoSure, but I think that's independent of what eMSF was describing. From libgcc/gthr.h: /* If this file is compiled with threads support, it must #define __GTHREADS 1 to indicate that threads support is present. Also it has define function int __gthread_active_p () that returns 1 if thread system is active, 0 if not. I think the mechanism eMSF was describing (and the mechanism in the blogpost I linked) corresponds to __gthread_active_p(). I think the distinction between the two should be visible in some cases - for example, what happens for shared libraries that use std::shared_ptr and don't link libpthread, but are later used with a binary that does link libpthread?
- menaerus 1y agoHm, not sure. I can see that shared_ptr::_M_release [0] is implemented in terms of __exchange_and_add_dispatch [1] and which is implemented in terms of __is_single_threaded [2]. __is_single_threaded will use __gthread_active_p iff __GTHREADS is not defined and <sys/single_threaded.h> header not included. Implementation of __gthread_active_p is indeed a runtime check [3] which AFAICS applies only to single-threaded programs. Perhaps the shared-library use-case also fits here? Strange optimization IMHO so I wonder what was the motivation behind it. The cost function being optimized in this case is depending on WORD being atomic [4] without actually using the atomics [5]. [0] https://codebrowser.dev/llvm/include/c++/11/bits/shared_ptr_base.h.html#165 https://codebrowser.dev/llvm/include/c++/11/bits/shared_ptr_... [1] https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.html#98 https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.... [2] https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.html#47 https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.... [3] https://codebrowser.dev/kde/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h.html#181 https://codebrowser.dev/kde/include/x86_64-linux-gnu/c++/11/... [4] https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.html#84 https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.... [5] https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h.html#66 https://codebrowser.dev/llvm/include/c++/11/ext/atomicity.h....
- aw1621107 1y ago
- grogers 1y agoPeople assume non-existent guarantees such as?
- izabera 1y ago"is shared_ptr thread safe?" is a classic question asked thousands of times. the answer by the way is "it's as thread safe as a regular pointer"
- loeg 1y agoOP specifically mentioned contention, though -- not marginally higher cost of atomic inc/dec vs plain inc/dec. > For our use case, we in fact do not use std::shared_ptr in our implementation, but instead a single-threaded shared_ptr-like class that has no atomics (to avoid cross-core contention). A single-threaded program will not have cross-core contention whether it uses std::atomic<> refcounts or plain integer refcounts, period. You're right that non-atomic refcounts can be anywhere from somewhat cheaper to a lot cheaper than atomic refcounts, depending on that platform. But that is orthogonal to cross-core contention.
- vlovich123 1y agoCan’t you have cross core contention just purely because of other processes doing atomics that happen to have a cache line address collision in the lock broadcast?
- SkiFire13 1y ago> not marginally higher cost of atomic inc/dec vs plain inc/dec. Note that the difference is not so marginal, and the difference is not just in hardware instructions as the non-atomic operations generally allow for more optimizations by the compiler.
- loeg 1y agoThe actual intrinsic is like 8-9 cycles on Zen4 or Ice Lake (vs 1 for plain add). It's something if you're banging on it in a hot loop, but otherwise not a ton. (If refcounting is hot in your design, your design is bad.) It's comparable to like, two integer multiplies, or a single integer division. Yes, there is some effect on program order.