diff --git a/cpp/particles/lock_free_bool_array.hpp b/cpp/particles/lock_free_bool_array.hpp index 4e5ad31b6274ee82b1dd99b0a8b87eba97fb64b7..ae5eb0d4f97420f08954595cb1c7ecd8fa78b080 100644 --- a/cpp/particles/lock_free_bool_array.hpp +++ b/cpp/particles/lock_free_bool_array.hpp @@ -27,31 +27,61 @@ #define LOCK_FREE_BOOL_ARRAY_HPP #include <vector> -#include <memory> +#include <atomic> +#include <unistd.h> +#include <cstdio> +#include <omp.h> + class lock_free_bool_array{ - std::vector<std::unique_ptr<long int>> keys; + static const int Available = 0; + static const int Busy = 1; + static const int NoOwner = -1; + + struct Locker { + Locker() : lock(Available), ownerId(NoOwner), counter(0) {} + std::atomic_int lock; + std::atomic_int ownerId; + int counter; + }; + + std::vector<std::unique_ptr<Locker>> keys; + public: - explicit lock_free_bool_array(const long int inNbKeys = 512){ + explicit lock_free_bool_array(const long int inNbKeys = 1024){ keys.resize(inNbKeys); - for(std::unique_ptr<long int>& k : keys){ - k.reset(new long int(0)); + for(auto& k : keys){ + k.reset(new Locker()); } } void lock(const long int inKey){ - volatile long int* k = keys[inKey%keys.size()].get(); - long int res = 1; - while(res == 1){ - res = __sync_val_compare_and_swap(k, 0, res); + Locker* k = keys[inKey%keys.size()].get(); + if(k->ownerId.load() != omp_get_thread_num()){ + int expected = Available; + while(!std::atomic_compare_exchange_strong(&k->lock, &expected, Busy)){ + usleep(1); + } + k->ownerId.store(omp_get_thread_num()); + k->counter = 0; // must remain } + k->counter += 1; + assert(k->lock.load() == Busy); + assert(k->counter >= 1); + assert(k->ownerId.load() == omp_get_thread_num()); } void unlock(const long int inKey){ - volatile long int* k = keys[inKey%keys.size()].get(); - assert(k && *k); - (*k) = 0; + Locker* k = keys[inKey%keys.size()].get(); + assert(k->lock.load() == Busy); + assert(k->counter >= 1); + assert(k->ownerId.load() == omp_get_thread_num()); + k->counter -= 1; + if(k->counter == 0){ + k->ownerId.store(NoOwner); + k->lock.store(Available); + } } };