feat(util/shared_mutex): add shared_mutex object, this is a temporary replacement for std::shared_mutex that will be available in C++11
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
2ac594a159
commit
596e4aeb57
4 changed files with 144 additions and 1 deletions
|
@ -9,6 +9,7 @@ Author: Leonardo de Moura
|
|||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include "util/shared_mutex.h"
|
||||
|
||||
void foo() {
|
||||
static thread_local std::vector<int> v(1024);
|
||||
|
@ -26,6 +27,30 @@ static void tst1() {
|
|||
}
|
||||
}
|
||||
|
||||
static void tst2() {
|
||||
unsigned N = 10;
|
||||
unsigned n = 1;
|
||||
lean::shared_mutex mut;
|
||||
std::vector<std::thread> threads;
|
||||
for (unsigned i = 0; i < N; i++) {
|
||||
threads.emplace_back([&]() {
|
||||
unsigned sum = 0;
|
||||
{
|
||||
lean::shared_lock lock(mut);
|
||||
for (unsigned i = 0; i < 1000000; i++)
|
||||
sum += n;
|
||||
}
|
||||
{
|
||||
lean::unique_lock lock(mut);
|
||||
std::cout << sum << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
for (unsigned i = 0; i < N; i++)
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
int main() {
|
||||
tst2(); return 0;
|
||||
tst1();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
add_library(util trace.cpp debug.cpp name.cpp exception.cpp
|
||||
hash.cpp escaped.cpp bit_tricks.cpp safe_arith.cpp ascii.cpp
|
||||
memory.cpp)
|
||||
memory.cpp shared_mutex.cpp)
|
||||
|
|
70
src/util/shared_mutex.cpp
Normal file
70
src/util/shared_mutex.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
// C++11 does not support std::shared_mutex and std::shared_lock yet.
|
||||
// This piece of Code is based on the proposal for C++14
|
||||
#include "util/shared_mutex.h"
|
||||
|
||||
namespace lean {
|
||||
shared_mutex::shared_mutex():m_state(0) {}
|
||||
shared_mutex::~shared_mutex() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
}
|
||||
|
||||
void shared_mutex::lock() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while (m_state & write_entered)
|
||||
m_gate1.wait(lock);
|
||||
m_state |= write_entered;
|
||||
while (m_state & readers)
|
||||
m_gate2.wait(lock);
|
||||
}
|
||||
|
||||
bool shared_mutex::try_lock() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_state == 0) {
|
||||
m_state = write_entered;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void shared_mutex::unlock() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_state = 0;
|
||||
m_gate1.notify_all();
|
||||
}
|
||||
|
||||
void shared_mutex::lock_shared() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
while ((m_state & write_entered) || (m_state & readers) == readers)
|
||||
m_gate1.wait(lock);
|
||||
unsigned num_readers = (m_state & readers) + 1;
|
||||
m_state &= ~readers;
|
||||
m_state |= num_readers;
|
||||
}
|
||||
|
||||
bool shared_mutex::try_lock_shared()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
unsigned num_readers = m_state & readers;
|
||||
if (!(m_state & write_entered) && num_readers != readers) {
|
||||
++num_readers;
|
||||
m_state &= ~readers;
|
||||
m_state |= num_readers;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void shared_mutex::unlock_shared() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
unsigned num_readers = (m_state & readers) - 1;
|
||||
m_state &= ~readers;
|
||||
m_state |= num_readers;
|
||||
if (m_state & write_entered) {
|
||||
if (num_readers == 0)
|
||||
m_gate2.notify_one();
|
||||
} else {
|
||||
if (num_readers == readers - 1)
|
||||
m_gate1.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
48
src/util/shared_mutex.h
Normal file
48
src/util/shared_mutex.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
// C++11 does not support std::shared_mutex and std::shared_lock yet.
|
||||
// This piece of Code is based on the proposal for C++14
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <climits>
|
||||
|
||||
namespace lean {
|
||||
class shared_mutex {
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_gate1;
|
||||
std::condition_variable m_gate2;
|
||||
unsigned m_state;
|
||||
|
||||
static constexpr unsigned write_entered = 1u << (sizeof(unsigned)*8 - 1);
|
||||
static constexpr unsigned readers = ~write_entered;
|
||||
|
||||
public:
|
||||
shared_mutex();
|
||||
~shared_mutex();
|
||||
|
||||
shared_mutex(shared_mutex const &) = delete;
|
||||
shared_mutex(shared_mutex &&) = delete;
|
||||
shared_mutex& operator=(shared_mutex const &) = delete;
|
||||
shared_mutex&& operator=(shared_mutex &&) = delete;
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
void unlock_shared();
|
||||
};
|
||||
|
||||
class shared_lock {
|
||||
shared_mutex & m_mutex;
|
||||
public:
|
||||
shared_lock(shared_mutex & m):m_mutex(m) { m_mutex.lock_shared(); }
|
||||
~shared_lock() { m_mutex.unlock_shared(); }
|
||||
};
|
||||
|
||||
class unique_lock {
|
||||
shared_mutex & m_mutex;
|
||||
public:
|
||||
unique_lock(shared_mutex & m):m_mutex(m) { m_mutex.lock(); }
|
||||
~unique_lock() { m_mutex.unlock(); }
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue