2015-06-21 23 views
4

我有一个执行自旋锁:旋转锁定栈及记忆力障碍(C++)

class Spinlock { 
public: 
    void Lock() { 
     while (true) { 
      if (!_lock.test_and_set(std::memory_order_acquire)) { 
       return; 
      } 
     } 
    } 

    void Unlock() { 
     _lock.clear(std::memory_order_release); 
    } 

private: 
    std::atomic_flag _lock; 
}; 

我用环形锁类:

class SpinlockedStack { 
public: 
    SpinlockedStack() : _head(nullptr) { 
    } 

    ~SpinlockedStack() { 
     while (_head != nullptr) { 
      Node* node = _head->Next; 
      delete _head; 
      _head = node; 
     } 
    } 

    void Push(int value) { 
     _lock.Lock(); 
     _head = new Node(value, _head); 
     _lock.Unlock(); 
    } 

    bool TryPop(int& value) { 
     _lock.Lock(); 

     if (_head == nullptr) { 
      value = NULL; 
      _lock.Unlock(); 
      return false; 
     } 

     Node* node = _head; 
     value = node->Value; 
     _head = node->Next; 

     delete node; 

     _lock.Unlock(); 

     return true; 
    } 

private: 
    struct Node { 
     int Value; 
     Node* Next; 

     Node(int value, Node* next) : Value(value), Next(next) { 
     } 
    }; 

    Node* _head; 
    Spinlock _lock; 
}; 

我知道我应该把记忆障碍。我可以使用原子变量:

struct Node { 
    int Value; 
    std::atomic<Node*> Next; 

    Node(int value) : Value(value) { 
    } 
}; 

std::atomic<Node*> _head; 
Spinlock _lock; 
... 

void Push(int value) { 
    _lock.Lock(); 

    Node* currentHead = _head.load(std::memory_order_acquire); 

    Node* newHead = new Node(value); 
    newHead->Next.store(currentHead, std::memory_order_relaxed); 

    _head.store(newHead, std::memory_order_release); 

    _lock.Unlock(); 
} 

bool TryPop(int& value) { 
    _lock.Lock(); 

    Node* currentHead = _head.load(std::memory_order_acquire); 

    if (currentHead == nullptr) { 
     value = NULL; 
     _lock.Unlock(); 
     return false; 
    } 

    value = currentHead->Value; 
    _head.store(currentHead->Next.load(std::memory_order_relaxed), std::memory_order_release); 

    delete currentHead; 

    _lock.Unlock(); 

    return true; 
} 

我也可以用atomic_thread_fence():

struct Node { 
    int Value; 
    Node* Next; 

    Node(int value) : Value(value) { 
    } 
}; 

Node* _head; 
Spinlock _lock; 

... 

void Push(int value) { 
    _lock.Lock(); 

    Node* currentHead = _head; 

    std::atomic_thread_fence(std::memory_order_acquire); 

    Node* newHead = new Node(value); 

    newHead->Next = currentHead; 

    std::atomic_thread_fence(std::memory_order_release); 

    _head = newHead; 

    _lock.Unlock(); 
} 

bool TryPop(int& value) { 
    _lock.Lock(); 

    std::atomic_thread_fence(std::memory_order_acquire); 

    Node* currentHead = _head; 

    if (currentHead == nullptr) { 
     value = NULL; 
     _lock.Unlock(); 
     return false; 
    } 

    value = currentHead->Value; 

    std::atomic_thread_fence(std::memory_order_acquire); 

    Node* nextNead = currentHead->Next; 

    std::atomic_thread_fence(std::memory_order_release); 

    _head = nextNead; 

    delete currentHead; 

    _lock.Unlock(); 

    return true; 
} 

我的问题:

  1. 不要我把记忆障碍是什么?
  2. 更好的是在这种情况下(原子变量或atomic_thread_fence)以及为什么使用?

回答

1

锁的获取已经确立了你所需要的内存保证。

当一个线程释放锁,它必须写入原子标志。这保证了当下一个线程获得锁并且看到对该标志的写入时,获取线程保证在写入该标志之前看到释放线程所做的所有写操作。

在你应该使用类似RAII以确保您的锁在任何情况下发布的旁注。

你也有ATOMIC_FLAG_INIT初始化你的锁,否则它是不确定的状态。