std::lock_guard
とstd::unique_lock
はなぜテンプレートタイプとしてロックタイプを指定する必要がありますか?std :: lock_guard/std :: unique_lockが型消去を使用しないのはなぜですか?
次の代替方法を検討してください。
#include <type_traits>
#include <mutex>
#include <chrono>
#include <iostream>
namespace detail {
struct locker_unlocker_base {
virtual void lock() = 0;
virtual void unlock() = 0;
};
template<class Mutex>
struct locker_unlocker : public locker_unlocker_base {
locker_unlocker(Mutex &m) : m_m{&m} {}
virtual void lock() { m_m->lock(); }
virtual void unlock() { m_m->unlock(); }
Mutex *m_m;
};
}
今te_lock_guard
、型消去ロックガード、単に配置-ニュースオブジェクト:まず、detail
名前空間で、型消去クラス(非テンプレート抽象基底クラス、およびテンプレートの派生クラス)があります私は標準ライブラリのクラス対パフォーマンスをチェックしました
class te_lock_guard {
public:
template<class Mutex>
te_lock_guard(Mutex &m) {
new (&m_buf) detail::locker_unlocker<Mutex>(m);
reinterpret_cast<detail::locker_unlocker_base *>(&m_buf)->lock();
}
~te_lock_guard() {
reinterpret_cast<detail::locker_unlocker_base *>(&m_buf)->unlock();
}
private:
std::aligned_storage<sizeof(detail::locker_unlocker<std::mutex>), alignof(detail::locker_unlocker<std::mutex>)>::type m_buf;
};
:
int main() {
constexpr std::size_t num{999999};
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
for(size_t i = 0; i < num; ++i) {
std::mutex m;
te_lock_guard l(m);
}
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
}
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
for(size_t i = 0; i < num; ++i) {
std::mutex m;
std::unique_lock<std::mutex> l(m);
}
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
}
}
(動的なメモリ割り当てなし)を構築し、正しいタイプの
-O3
でg ++を使用すると、統計的に有意なパフォーマンスの低下はありません。
あなたのために '統計的に有意義なものは何ですか?ネイティブの実装は、それを4〜5回実行すると高速に見えました。あなたが見ているものが重要でないと分かりません。そしてなぜ現在の選択肢よりも遅いデフォルトの実装を選択するのですか?しかし、質問自体はかなりinteresstingです。良い人が代替を測定しました。 – Hayt
実際にタイプ名をもう一度入力しなくてはいけない場合は、関数テンプレートを使用することができます: 'auto && lock = guard_me(mx);'([Demo](https://ideone.com/ysxJEz) 。) –
@Hayt私が意味したのは、統計的置換検査は、彼らが同じ分布から来たという仮説を棄却しなかったということです。私にとって、複雑な代替案は実際には偶然にも時にはより高速になることがあります。統計を扱うと、「彼らは同じスピードで走っている」などの強い声明を避けようとしています。 –