加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

旋转锁定堆栈和内存屏障(C)

发布时间:2020-12-16 07:12:47 所属栏目:百科 来源:网络整理
导读:我有一个实现自旋锁: 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 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;
};

我在下面使用SpinLock类:

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;
}

我的问题:

>我是否放置了记忆障碍?
>在这种情况下最好使用什么(原子变量或atomic_thread_fence)以及为什么?

解决方法

获取锁已经确定了您需要的内存保证.

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

在旁注中,您应该使用RAII之类的东西来确保在所有情况下释放锁定.

此外,您必须使用ATOMIC_FLAG_INIT初始化锁定,否则它将处于未定义状态.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读