#include <iostream>
#include <memory>
#include <queue>
#include <future>
#include <iostream>
#include <mutex>
class RWLocker final
{
mutable std::mutex general_lock_;
mutable std::mutex write_lock_;
mutable std::mutex read_lock_;
mutable std::size_t number_of_readers_ = 0;
RWLocker (const RWLocker &) = delete;
RWLocker & operator= (const RWLocker &) = delete;
public:
RWLocker () = default;
//Only read and write abstractions can work with RWLocker
friend class ReadGuard;
friend class WriteGuard;
};
class WriteGuard final
{
const RWLocker & locker_;
WriteGuard (const WriteGuard &) = delete;
WriteGuard & operator= (const WriteGuard &) = delete;
public:
//Strong exception guarantee
explicit WriteGuard (const RWLocker & input_lock) :
locker_ { input_lock }
{
locker_.general_lock_.lock ();
locker_.write_lock_.lock ();
locker_.general_lock_.unlock ();
}
~WriteGuard ()
{
//Anyway UB if unlock fails
locker_.write_lock_.unlock ();
}
};
class ReadGuard final
{
const RWLocker & locker_;
ReadGuard (const ReadGuard &) = delete;
ReadGuard & operator= (const ReadGuard &) = delete;
public:
//Strong exception guarantee
explicit ReadGuard (const RWLocker & input_lock) :
locker_ { input_lock }
{
locker_.general_lock_.lock ();
locker_.read_lock_.lock ();
locker_.general_lock_.unlock ();
if (0 < ++locker_.number_of_readers_)
locker_.write_lock_.lock ();
locker_.read_lock_.unlock ();
}
~ReadGuard ()
{
//Anyway UB if unlock fails
if (1 > --locker_.number_of_readers_)
locker_.write_lock_.unlock ();
locker_.read_lock_.unlock ();
}
};
template<typename T>
std::chrono::milliseconds measure_execution_time(T _t)
{
std::chrono::steady_clock clock;
auto tp_begin = clock.now();
_t();
auto tp_end = clock.now();
auto execution_time =
std::chrono::duration_cast<std::chrono::milliseconds>(
tp_end.time_since_epoch() - tp_begin.time_since_epoch()
);
return execution_time;
}
int main()
{
const int n = 10000000;
{
RWLocker locker;
auto time = measure_execution_time([n, &locker](){
long c = 0;
for (int i = 0; i< n; ++i)
{
ReadGuard guard(locker);
c += i;
}
});
std::cout << "Yoba mutex: " << time.count() << std::endl;
}
{
std::mutex m;
auto time = measure_execution_time([n, &m](){
long c = 0;
for (int i = 0; i< n; ++i)
{
std::lock_guard<std::mutex> lock(m);
c += i;
}
});
std::cout << "Mutex: " << time.count() << std::endl;
}
return 0;
}