繁体   English   中英

shared_mutex锁定顺序

[英]shared_mutex lock ordering

我的印象是,如果获得了太多的共享锁,那么使用c ++ 17的std::shared_mutex实现的多个读者/单个编写器模式可能永远不会放弃唯一锁。

在挖掘cppreference之后 ,我不确定是这样的。 特别是:

单个互斥锁上的所有锁定和解锁操作都在一个总订单中进行

例如,给定shared_mutex上的以下操作,我相信unique_lock可能永远不会获取。 假设shared_locks限量的shared_locks ,并且这些锁在第一个shared_locks发布之前获取。

shared_lock
shared_lock
shared_lock

unique_lock

shared_lock
[...]
shared_lock

具有以下特点。

{ shared_lock, shared_lock, shared_lock, shared_lock, ..., shared_lock } // never releases

unique_lock

但是,如果我正确理解cppreference,一旦unique_lock尝试获取,连续的shared_locks将阻塞,直到unique_lock被释放。 给出以下线程特征。

{ shared_lock, shared_lock, shared_lock} // simultaneous

unique_lock

{ shared_lock, ..., shared_lock} // waits, then simultaneous

所以我的问题是, std::shared_mutex在共享锁和唯一锁之间保持排序? 防止由于获取了大量的shared_locks而永远不会获取unique_locks的情况。

编辑:

这是一个帮助理解问题的代码示例,为了后人的缘故。 在MSVC 2019上, shared_mutex是安全的,并且根据需要进行排序。 unique_lock确实在“无限”数量的shared_locks之前得到处理。

现在的问题是,这个平台是否依赖?

#include <chrono>
#include <cstdio>
#include <mutex>
#include <shared_mutex>
#include <thread>
#include <vector>

using namespace std::chrono_literals;

std::shared_mutex smtx;

int main(int, char**) {

    std::vector<std::thread> threads;

    auto read_task = [&]() {
        std::shared_lock l{ smtx };
        printf("read\n");
        std::this_thread::sleep_for(1s);
    };

    auto write_task = [&]() {
        std::unique_lock l{ smtx };
        printf("write\n");
        std::this_thread::sleep_for(1s);
    };

    // Create a few reader tasks.
    threads.emplace_back(read_task);
    threads.emplace_back(read_task);
    threads.emplace_back(read_task);


    // Try to lock a unique_lock before read tasks are done.
    std::this_thread::sleep_for(1ms);
    threads.emplace_back(write_task);

    // Then, enque a gazillion read tasks.
    // Will the unique_lock be locked? [drum roll]

    // Would be while(true), 120 should be enough for demo
    for (size_t i = 0; i < 120; ++i) {
        std::this_thread::sleep_for(1ms);
        threads.emplace_back(read_task);
    }

    for (auto& t : threads) {
        t.join();
    }
}

产出:

read
read
read
write
read
...
read

std shared_mutex规范未指定共享锁的优先级,也不指定唯一锁。 也没有任何API可以设置这样的优先级。 缺乏优先权规范的原始动机之一是存在如此处所解释Alexander Terekhov算法

第二个动机是解释shared_mutex中缺少读写器优先级策略。 这是由于算法归功于Alexander Terekhov,它让操作系统决定下一个获得锁定的线程,而不关心是否正在寻找一个独特的锁或共享锁。 这导致完全缺乏读者或作家的饥饿。 这很公平。

标准规范不需要Alexander Terekhov算法。 然而,至少我希望,这种算法将是首选,因为缺乏规范或API优先于读者而不是编写者,反之亦然。

有关Alexander Terekhov算法的更多细节以及一些代码,这些代码在此SO答案中展示了它的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM