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