c++ - Lightweight spinlocks built from GCC atomic operations? -
i'd minimize synchronization , write lock-free code when possible in project of mine. when absolutely necessary i'd love substitute light-weight spinlocks built atomic operations pthread , win32 mutex locks. understanding these system calls underneath , cause context switch (which may unnecessary quick critical sections spinning few times preferable).
the atomic operations i'm referring documented here: http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/atomic-builtins.html
here example illustrate i'm talking about. imagine rb-tree multiple readers , writers possible. rbtree::exists() read-only , thread safe, rbtree::insert() require exclusive access single writer (and no readers) safe. code:
class intsettest { private: unsigned short lock; rbtree<int>* myset; public: // ... void add_number(int n) { // aquire once locked==false (atomic) while (__sync_bool_compare_and_swap(&lock, 0, 0xffff) == false); // perform thread-unsafe operation on set myset->insert(n); // unlock (atomic) __sync_bool_compare_and_swap(&lock, 0xffff, 0); } bool check_number(int n) { // increment once lock below 0xffff u16 savedlock = lock; while (savedlock == 0xffff || __sync_bool_compare_and_swap(&lock, savedlock, savedlock+1) == false) savedlock = lock; // perform read-only operation bool exists = tree->exists(n); // decrement savedlock = lock; while (__sync_bool_compare_and_swap(&lock, savedlock, savedlock-1) == false) savedlock = lock; return exists; } };
(lets assume need not exception-safe)
is code indeed thread-safe? there pros/cons idea? advice? use of spinlocks bad idea if threads not concurrent?
thanks in advance. ;)
you need volatile
qualifier on lock
, , make sig_atomic_t
. without volatile
qualifier, code:
u16 savedlock = lock; while (savedlock == 0xffff || __sync_bool_compare_and_swap(&lock, savedlock, savedlock+1) == false) savedlock = lock;
may not re-read lock
when updating savedlock
in body of while-loop. consider case lock
0xffff. then, savedlock
0xffff prior checking loop condition, while
condition short-circuit prior calling __sync_bool_compare_and_swap
. since __sync_bool_compare_and_swap
wasn't called, compiler doesn't encounter memory barrier, might reasonably assume value of lock
hasn't changed underneath you, , avoid re-loading in savedlock
.
re: sig_atomic_t
, there's decent discussion here. same considerations apply signal handlers apply threads.
with these changes, i'd guess code thread-safe. still recommend using mutexes, though, since don't know how long rb-tree insert take in general case (per previous comments under question).
Comments
Post a Comment