首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++11递归原子自旋锁

C++11递归原子自旋锁
EN

Code Review用户
提问于 2015-07-02 14:36:31
回答 1查看 3K关注 0票数 8

你能回顾一下我的自旋锁实现吗?

代码语言:javascript
运行
复制
class spinlock {
private:
    static const std::thread::id lock_is_free;
    std::atomic<std::thread::id> lock_owner;
    int lock_count;

public:
    spinlock() : lock_owner(lock_is_free), lock_count(0) {
    }

    void lock() {
        static thread_local std::thread::id this_thread_local = std::this_thread::get_id();
        auto this_thread = this_thread_local;

        for (auto id = lock_is_free; ; id = lock_is_free) {
            if (lock_owner.compare_exchange_strong(id, this_thread, std::memory_order_acquire, std::memory_order_relaxed)) { ++lock_count; break; }
            id = this_thread;
            if (lock_owner.compare_exchange_strong(id, this_thread, std::memory_order_acquire, std::memory_order_relaxed)) { ++lock_count; break; }
        }
    }

    void unlock() {
        assert(lock_owner.load(std::memory_order_relaxed) == std::this_thread::get_id());
        if (lock_count > 0 && --lock_count == 0) {
            lock_owner.store(lock_is_free, std::memory_order_release);
        }
    }
};

const std::thread::id spinlock::lock_is_free;
EN

回答 1

Code Review用户

回答已采纳

发布于 2015-07-06 14:26:06

使用TLS

我还没有完全接受你对TLS的使用。对我来说,这看起来是一个不成熟的优化,也就是说,如果你已经测量了,并且它提高了你的性能,然后保持它。

静态成员

我认为没有这个静态成员会更好,但这是非常主观的。

可读性

你的代码在这里:

代码语言:javascript
运行
复制
    for (auto id = lock_is_free; ; id = lock_is_free) {
        if (lock_owner.compare_exchange_strong(id, this_thread, std::memory_order_acquire, std::memory_order_relaxed)) { ++lock_count; break; }
        id = this_thread;
        if (lock_owner.compare_exchange_strong(id, this_thread, std::memory_order_acquire, std::memory_order_relaxed)) { ++lock_count; break; }
    }

对我来说很难读懂。事实上,我很难理解这种行为是什么。在我看来你真正想要的是:

代码语言:javascript
运行
复制
// If we're being locked recursively, this will always compare false
// (insert your desired memory_order here) because no one can fiddle
// with `lock_owner` while we have the lock. If we're not entering
// recursively then this will always compare true because the thread
// doing the checking can only be in one place at one time. 
if(lock_owner.load() != this_thread){
    // Okay so it's not a recursive call.
    do{
        auto id = lock_is_free;
    }while(!lock_owner.compare_exchange_weak(id, this_thread, 
                                             std::memory_order_acquire, 
                                             std::memory_order_relaxed));
}
// Okay in any event, recursive or not we have the lock now.
lock_count++;
return;

注意:我将compare_exchange_strong更改为compare_exchange_weak,这是在循环中按Std::原子::比较_交换(cppreference.com)调用compare_exchange时推荐的。

我更喜欢这种unlock()的实现

代码语言:javascript
运行
复制
void unlock(){
    assert(lock_owner.load() == std::this_thread::get_id());
    assert(lock_count != 0);

    --lock_count;
    if(lock_count == 0){
        lock_owner.store(lock_is_free, std::memory_order_release);
    }
}

按照std::mutex::unlock()的样式,在调用线程不拥有锁时调用unlock是未定义的行为,我们可以简单地使用这两个断言来满足自己的要求,以便在调试时提供帮助。

票数 6
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/95590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档