5 ms·
Despite the quote, it's just not true that relaxed atomics will give the same kind of performance. They may, but they may not, depending on the situation. The i
by mehrdadn 6y ago
Despite the quote, it's just not true that relaxed atomics will give the same kind of performance. They may, but they may not, depending on the situation. The issue with them is that they're still atomic throughout the entire program, even in the situations where you can guarantee there are no other threads running and hence don't need atomicity. (Perhaps in particular scenarios, like with small inputs, you never even spawn additional threads to begin with.) For native-sized integers, ensuring atomicity might or might have overhead depending on the implementation. But it will at least have overhead for larger objects.
- PaulDavisThe1st 6y ago> But it will at least have overhead for larger objects. Given that there's essentially no way to do atomic operations on larger objects (than machine-level types), all std::atomic<> for such types must involve a mutex, and are therefore guaranteed to have performance implications. std::atomic<T> provides syntax that treats std::atomic<int> and std::atomic<MyHugeObject> in precisely the same way. This is useful, but entirely misleading if you care about performance.
- mehrdadn 6y agoYou're arguing for my point, not against it. (Though your basis for it isn't even true; HTM could avoid mutexes.)
- PaulDavisThe1st 6y agoHTM?
- mehrdadn 6y agoHardware transactional memory. TSX-NI in Intel's case.
- pkolaczk 6y agoThey don't have to involve a mutex but some kind of synchronisation. A sequential lock is another way of efficiently implementing that, without blocking the happy read path. Instead of locking the large object, it detects if a read was atomic and retries if it was not.
- PaulDavisThe1st 6y agoTechnically speaking, this is still not atomic, merely lock-free. Still very useful, but not semantically equivalent to the store or load of a 32 or 64 bit integer value (for example).
- pkolaczk 6y agoSemantically it is atomic, because if the seq lock is implemented as a separate abstraction, the caller never observes a partially written value (no tearing). Retrying a broken read is just an implementation detail.
- lmm 6y agoIf you can really guarantee that there are no other threads running, surely you can explain that guarantee to the compiler so that it can make use of it.
- eloff 6y agoDoing so may likely require creating a separate code path for threads = 1 case, which is probably not worth the effort involved.
- eloff 6y agoRelaxed atomics translate to native loads and stores. In theory there is no cost to them apart from the compiler barrier which prevents other loads/stores from moving past them, depending on the case. For larger objects, std::atomic uses a mutex, so it's kind of silly anyway. If you wanted a mutex, better to make it explicit.
- mehrdadn 6y ago> Relaxed atomics translate to native loads and stores Native loads and stores with lock... and that is on x86. https://gcc.godbolt.org/z/asKna4 https://gcc.godbolt.org/z/asKna4 Definitely not the same as a native operation. > In theory there is no cost to them This isn't theory though. > apart from the compiler barrier which prevents other loads/stores from moving past them, depending on the case Why apart from? Why not include this obvious deficiency? It's a legitimate objection and a pretty important component to my point you can't just brush aside out of inconvenience. > For larger objects, std::atomic uses a mutex, so it's kind of silly anyway. If you wanted a mutex, better to make it explicit. Better in your eyes. Clearly not in the standard writers', or they wouldn't have introduced the functionality. My only point is if people do decide to use it (the reasons not being the subject of this debate), they come across this shortcoming.