From f066e8d59f41a0f5f4d60908bc53608a8250978b Mon Sep 17 00:00:00 2001
From: Berenger Bramas <Berenger.Bramas@inria.fr>
Date: Wed, 19 May 2021 14:37:51 +0200
Subject: [PATCH] Second bug solved (update the lock free bool array)

---
 cpp/particles/lock_free_bool_array.hpp | 54 ++++++++++++++++++++------
 1 file changed, 42 insertions(+), 12 deletions(-)

diff --git a/cpp/particles/lock_free_bool_array.hpp b/cpp/particles/lock_free_bool_array.hpp
index 4e5ad31b..ae5eb0d4 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);
+        }
     }
 };
 
-- 
GitLab