foo
類有一個方法bar
。根據某些同步協議,特定foo
對象的bar
方法將在任何時間點僅由最多一個線程調用。一種高效非強制實施,檢驗互斥
我想補充一個非常輕巧verification_mutex
驗證這一/調試同步濫用。類似地,將用於常規的互斥體:但是
class foo {
public:
void bar() {
std::lock_guard<verification_mutex> lk{m};
...
}
private:
mutable verification_mutex m;
};
,它本身不會必然鎖定或解鎖任何東西。如果檢測到多線程同時訪問,它將只是throw
。重點是儘可能降低其運行時間佔用(包括對其他代碼的影響,例如通過memory barriers)。
這裏是實現verification_mutex
三個選項:
- 的包裝紙圍繞
std::mutex
,但通過檢查trylock
成功實現lock
(這是剛拿到的想法;顯然不是非常快) - 一個原子變量,記錄了當前的「鎖定」線程ID,原子操作爲
exchange
(請參見下面的實現草圖)。 - 與2相同,但沒有原子。
這些是正確或不正確(尤其是2和ESP 3)?他們將如何影響性能(特別是周圍的代碼)?有沒有一個完全優越的選擇?下面
編輯通過@SergeyA答案是好的,但我特別好奇的記憶障礙。一個不利用它們的解決方案將會很好,如果答案給出一些直觀的解釋,爲什麼任何解決方案都會失敗。
實現素描
#include <atomic>
#include <thread>
#include <functional>
class verification_mutex {
public:
verification_mutex() : m_holder{0}{}
void lock() {
if(m_holder.exchange(get_this_thread_id()) != 0)
throw std::logic_error("lock");
}
void unlock() {
if(m_holder.exchange(0) != get_this_thread_id())
throw std::logic_error("unlock");
}
bool try_lock() {
lock();
return true;
}
private:
static inline std::size_t get_this_thread_id() {
return std::hash<std::thread::id>()(std::this_thread::get_id());
}
private:
std::atomic_size_t m_holder;
};
的的tryLock具有實際持有鎖,否則你無法檢測,如果其他線程是「在那裏」。所以它不會比鎖更快。你需要知道這個錯誤有多強烈?可靠的,還是這只是測試? – Yakk
你爲什麼想要重入鎖? – SergeyA
此外,請注意添加任何類型的同步將你的減緩由於內存屏障效應(以及同步無記憶障礙是無用的) – SergeyA