![](/img/trans.png)
[英]Why ever use std::mutex instead of boost::shared_mutex?
[英]Why is std::mutex taking a long, highly irregular amount of time to be shared?
此代碼演示了兩個線程之間共享互斥鎖,但幾乎所有時間都有一個線程。
#include <thread>
#include <mutex>
#include <iostream>
#include <unistd.h>
int main ()
{
std::mutex m;
std::thread t ([&] ()
{
while (true)
{
{
std::lock_guard <std::mutex> thread_lock (m);
sleep (1); // or whatever
}
std::cerr << "#";
std::cerr.flush ();
}
});
while (true)
{
std::lock_guard <std::mutex> main_lock (m);
std::cerr << ".";
std::cerr.flush ();
}
}
在Ubuntu 18.04 4.15.0-23-generic上用g ++ 7.3.0編譯。
輸出是#
和的混合.
字符,顯示共享互斥鎖,但模式令人驚訝。 通常是這樣的:
.......#####..........................##################......................##
即thread_lock
鎖定互斥鎖很長一段時間。 幾秒甚至幾十秒后, main_lock
接收控制(簡要地)然后thread_lock
將其恢復並保持多年。 調用std::this_thread::yield()
不會改變任何東西。
為什么兩個互斥鎖不太可能獲得鎖定,如何以均衡的方式共享互斥鎖?
std::mutex
的設計並不公平。 它不能保證鎖定的順序是保持的,你要么幸運得到鎖定。
如果你想要更公平,可以考慮像這樣使用std::condition_variable
:
#include <thread>
#include <mutex>
#include <iostream>
#include <condition_variable>
#include <unistd.h>
int main ()
{
std::mutex m;
std::condition_variable cv;
std::thread t ([&] ()
{
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << "#";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
});
while (true)
{
std::unique_lock<std::mutex> lk(m);
std::cerr << ".";
std::cerr.flush ();
cv.notify_one();
cv.wait(lk);
}
}
制作std::mutex
會產生費用。 在C ++中,你不需要支付你不需要的東西。
你可以編寫一個鎖定對象,釋放鎖的一方不能成為下一個鎖定對象。 更高級,您可以寫一個只有在其他人等待時才會出現這種情況。
這是一個快速的,未經測試的公平互斥的刺:
struct fair_mutex {
void lock() {
auto l = internal_lock();
lock(l);
}
void unlock() {
auto l = internal_lock();
in_use = false;
if (waiting != 0) {
loser=std::this_thread::get_id();
} else {
loser = {};
}
cv.notify_one();
}
bool try_lock() {
auto l = internal_lock();
if (in_use) return false;
lock(l);
return true;
}
private:
void lock(std::unique_lock<std::mutex>&l) {
++waiting;
cv.wait( l, [&]{ return !in_use && std::this_thread::get_id() != loser; } );
in_use = true;
--waiting;
}
std::unique_lock<std::mutex> internal_lock() const {
return std::unique_lock<std::mutex>(m);
}
mutable std::mutex m;
std::condition_variable cv;
std::thread::id loser;
bool in_use = false;
std::size_t waiting = 0;
};
它是“公平的”,如果你有兩個線程爭奪資源,他們將輪流。 如果有人在等鎖,任何放棄鎖定的人都不會再抓住它。
但是,這是線程代碼。 所以我可能會讀完它,但我不相信我第一次嘗試寫任何東西。
您可以將此(以不斷增加的成本)擴展為n-way fair(甚至是omega-fair),如果有多達N個元素在等待,它們都會在釋放線程獲得另一個機會之前輪到他們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.