scx*_*scx 7 c++ multithreading mutex locking c++17
我的印象是,std::shared_mutex如果获取了太多共享锁,则使用c ++ 17实现的多读取器/单写入器模式可能永远不会放弃唯一锁。
在探究cppreference之后,我不确定是这种情况。具体来说:
单个互斥锁上的所有锁定和解锁操作均以单个总顺序发生
例如,鉴于对进行以下操作shared_mutex,我认为unique_lock可能永远不会获得。假设无限数量的shared_locks,并且这些锁在第一次shared_locks发行之前获得。
shared_lock
shared_lock
shared_lock
unique_lock
shared_lock
[...]
shared_lock
Run Code Online (Sandbox Code Playgroud)
具有以下特征。
{ shared_lock, shared_lock, shared_lock, shared_lock, ..., shared_lock } // never releases
unique_lock
Run Code Online (Sandbox Code Playgroud)
但是,如果我正确理解了cppreference,那么一旦unique_lock尝试获取cppreference,continuous shared_locks将会阻塞直到unique_lock释放。提供以下线程特征。
{ shared_lock, shared_lock, shared_lock} // simultaneous
unique_lock
{ shared_lock, ..., shared_lock} // waits, then simultaneous
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,std::shared_mutex共享锁和唯一锁之间是否保持顺序?防止unique_locks由于大量获取而永远无法获取的情况shared_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();
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
read
read
read
write
read
...
read
Run Code Online (Sandbox Code Playgroud)
stdshared_mutex规范没有指定共享锁或唯一锁的优先级。也没有任何 API 可以设置这样的优先级。缺乏优先级规范的原始动机之一是Alexander Terekhov 算法的存在,如此处所述。
第二个动机是解释 shared_mutex 中缺乏读写器优先级策略。这是由于 Alexander Terekhov 的一种算法,它让操作系统决定下一个获取锁的线程,而不关心正在寻找的是唯一锁还是共享锁。这导致读者完全缺乏或作者饥饿。这简直就是公平。
标准规范不需要 Alexander Terekhov 算法。然而,至少我希望该算法会成为首选,因为缺乏规范或 API 来优先选择读者而不是作者,反之亦然。
有关 Alexander Terekhov 算法的更多详细信息以及一些演示其行为的代码,请参阅此处的 SO 答案。