Browse Source

Created two versions of shared mutex:

- Normal - fast and efficient mutex
- Recursive - it may be less efficient on some platforms
master
Artyom Beilis 12 years ago
parent
commit
37ce2a6fca
7 changed files with 223 additions and 35 deletions
  1. +38
    -2
      booster/booster/thread.h
  2. +26
    -9
      booster/lib/thread/src/pthread.cpp
  3. +61
    -0
      booster/lib/thread/src/thread_win5.cpp
  4. +26
    -0
      booster/lib/thread/src/thread_win6.cpp
  5. +6
    -6
      booster/lib/thread/src/thread_winapi.cpp
  6. +58
    -10
      booster/lib/thread/test/test_thread.cpp
  7. +8
    -8
      src/views_pool.cpp

+ 38
- 2
booster/booster/thread.h View File

@@ -121,6 +121,43 @@ namespace booster {
};

///
/// \brief Recursuve Shared mutex or a.k.a. Read-Write Lock that can be recursively locked by \b readers
///
/// This class provides two options of locking unique - nobody but me can use the object
/// shared anybody with shared lock can use the object.
///
class BOOSTER_API recursive_shared_mutex : public noncopyable {
public:
recursive_shared_mutex();
~recursive_shared_mutex();
///
/// Same as unique_lock()
///
/// \note this function is not recursive
///
void lock() { unique_lock(); }
///
/// Acquire a unique lock on the object. \see booster::unique_lock
///
/// \note this function is not recursive
///
void unique_lock();
///
/// Acquire a shared lock on the object. \see booster::shared_lock
///
/// \note the shared_lock() member function is recursive, that means that same thread may acquire
/// it multiple times.
///
void shared_lock();
///
/// Release the lock
///
void unlock();
private:
struct data;
hold_ptr<data> d;
};
///
/// \brief Shared mutex or a.k.a. Read-Write Lock
///
/// This class provides two options of locking unique - nobody but me can use the object
@@ -141,8 +178,7 @@ namespace booster {
///
/// Acquire a shared lock on the object. \see booster::shared_lock
///
/// Note the shared_lock() member function is recursive, that means that same thread may acquire
/// it multiple times.
/// Note this function is not recursive
///
void shared_lock();
///


+ 26
- 9
booster/lib/thread/src/pthread.cpp View File

@@ -139,9 +139,6 @@ namespace booster {
void recursive_mutex::lock() { pthread_mutex_lock(&d->m); }
void recursive_mutex::unlock() { pthread_mutex_unlock(&d->m); }

#ifndef __APPLE__
/// This is normal implementation

struct shared_mutex::data { pthread_rwlock_t m; };
shared_mutex::shared_mutex() : d(new data)
{
@@ -155,9 +152,29 @@ namespace booster {
void shared_mutex::unique_lock() { pthread_rwlock_wrlock(&d->m); }
void shared_mutex::unlock() { pthread_rwlock_unlock(&d->m); }

#ifndef __APPLE__
//
// This is normal implementation
//
// Same as shared mutex under "Most platforms"
//
struct recursive_shared_mutex::data { pthread_rwlock_t m; };
recursive_shared_mutex::recursive_shared_mutex() : d(new data)
{
pthread_rwlock_init(&d->m,0);
}
recursive_shared_mutex::~recursive_shared_mutex()
{
pthread_rwlock_destroy(&d->m);
}
void recursive_shared_mutex::shared_lock() { pthread_rwlock_rdlock(&d->m); }
void recursive_shared_mutex::unique_lock() { pthread_rwlock_wrlock(&d->m); }
void recursive_shared_mutex::unlock() { pthread_rwlock_unlock(&d->m); }


#else // Darwin has broken recursive RW Lock
struct shared_mutex::data {
struct recursive_shared_mutex::data {
thread_specific_ptr<int> k;
pthread_rwlock_t m;
};
@@ -174,24 +191,24 @@ namespace booster {
}
}

shared_mutex::shared_mutex() : d(new data)
recursive_shared_mutex::recursive_shared_mutex() : d(new data)
{
pthread_rwlock_init(&d->m,0);
}
shared_mutex::~shared_mutex()
recursive_shared_mutex::~recursive_shared_mutex()
{
pthread_rwlock_destroy(&d->m);
}
void shared_mutex::shared_lock()
void recursive_shared_mutex::shared_lock()
{
int &counter = specific_key(d->k);
if(counter++ == 0)
pthread_rwlock_rdlock(&d->m);
}
void shared_mutex::unique_lock() {
void recursive_shared_mutex::unique_lock() {
pthread_rwlock_wrlock(&d->m);
}
void shared_mutex::unlock() {
void recursive_shared_mutex::unlock() {
int &counter = specific_key(d->k);
if(counter > 1) {
counter --;


+ 61
- 0
booster/lib/thread/src/thread_win5.cpp View File

@@ -49,6 +49,67 @@ namespace booster {
LeaveCriticalSection(&d->m);
}
struct shared_mutex::data {
mutex lock;
condition_variable can_lock;

int read_lock;
int write_lock;
int pending_lock;

};
shared_mutex::shared_mutex() : d(new data)
{
d->read_lock = 0;
d->write_lock = 0;
d->pending_lock = 0;
}
shared_mutex::~shared_mutex()
{
}
void shared_mutex::shared_lock()
{
booster::unique_lock<mutex> g(d->lock);
for(;;) {
if(d->write_lock == 0 && d->pending_lock == 0) {
d->read_lock++;
break;
}
else
d->can_lock.wait(g);
}

}
void shared_mutex::unique_lock()
{
booster::unique_lock<mutex> g(d->lock);
for(;;) {
if(d->write_lock == 0 && d->read_lock==0) {
d->write_lock = 1;
d->pending_lock = 0;
break;
}
else {
if(d->read_lock)
d->pending_lock = 1;
d->can_lock.wait(g);
}
}
}
void shared_mutex::unlock()
{
booster::unique_lock<mutex> g(d->lock);
if(d->write_lock) {
d->write_lock = 0;
d->pending_lock = 0;
d->can_lock.notify_all();
}
else if(d->read_lock) {
d->read_lock--;
if(d->read_lock == 0)
d->can_lock.notify_all();
}
}

namespace details {
struct event {


+ 26
- 0
booster/lib/thread/src/thread_win6.cpp View File

@@ -48,6 +48,32 @@ namespace booster {
LeaveCriticalSection(&d->m);
}
struct shared_mutex::data { SRWLOCK m; bool ex; };
shared_mutex::shared_mutex() : d(new data)
{
d->ex=false;
InitializeSRWLock(&d->m);
}
shared_mutex::~shared_mutex()
{
}
void shared_mutex::shared_lock() {
AcquireSRWLockShared(&d->m);
}
void shared_mutex::unique_lock() {
AcquireSRWLockExclusive(&d->m);
d->ex=true;
}
void shared_mutex::unlock() {
bool ex = d->ex;
if(ex) {
d->ex=false;
ReleaseSRWLockExclusive(&d->m);
}
else
ReleaseSRWLockShared(&d->m);
}

struct condition_variable::data { CONDITION_VARIABLE c; };

condition_variable::condition_variable() : d(new data)


+ 6
- 6
booster/lib/thread/src/thread_winapi.cpp View File

@@ -269,7 +269,7 @@ namespace booster {
void recursive_mutex::unlock() { LeaveCriticalSection(&d->m); }


struct shared_mutex::data {
struct recursive_shared_mutex::data {
mutex lock;
condition_variable can_lock;

@@ -287,17 +287,17 @@ namespace booster {
}

};
shared_mutex::shared_mutex() : d(new data)
recursive_shared_mutex::recursive_shared_mutex() : d(new data)
{
d->read_lock = 0;
d->write_lock = 0;
d->pending_lock = 0;
memset(&d->recursive_locks,0,sizeof(d->recursive_locks));
}
shared_mutex::~shared_mutex()
recursive_shared_mutex::~recursive_shared_mutex()
{
}
void shared_mutex::shared_lock()
void recursive_shared_mutex::shared_lock()
{
unsigned id = data::id();
booster::unique_lock<mutex> g(d->lock);
@@ -311,7 +311,7 @@ namespace booster {
}

}
void shared_mutex::unique_lock()
void recursive_shared_mutex::unique_lock()
{
booster::unique_lock<mutex> g(d->lock);
for(;;) {
@@ -327,7 +327,7 @@ namespace booster {
}
}
}
void shared_mutex::unlock()
void recursive_shared_mutex::unlock()
{
unsigned id = data::id();
booster::unique_lock<mutex> g(d->lock);


+ 58
- 10
booster/lib/thread/test/test_thread.cpp View File

@@ -100,11 +100,12 @@ struct cond_incrementer {
};


template<typename ShM>
struct rw_executor {
bool *flag;
bool read;
booster::mutex *flags_mutex;
booster::shared_mutex *mutex;
ShM *mutex;
void operator()() const
{
for(int i=0;i<20;i++) {
@@ -136,7 +137,7 @@ struct rw_executor {


struct rw_shared_thread {
booster::shared_mutex *lp;
booster::recursive_shared_mutex *lp;
bool *done;
void operator()() const
{
@@ -154,7 +155,7 @@ struct rw_shared_thread {
};

struct rw_unique_thread {
booster::shared_mutex *lp;
booster::recursive_shared_mutex *lp;
bool *done;
void operator()() const
{
@@ -293,7 +294,7 @@ int main()
t2.join();
t3.join();
}
std::cout << "Test rw_lock write lock" << std::endl;
std::cout << "Test shared_mutex write lock" << std::endl;
{
variable = 0;
booster::shared_mutex m;
@@ -304,7 +305,18 @@ int main()
t2.join();
TEST(variable == 10);
}
std::cout << "Test rw_lock shared/write lock" << std::endl;
std::cout << "Test recursive_shared_mutex write lock" << std::endl;
{
variable = 0;
booster::shared_mutex m;
incrementer<booster::shared_mutex> inc = { &m };
booster::thread t1(inc);
booster::thread t2(inc);
t1.join();
t2.join();
TEST(variable == 10);
}
std::cout << "Test shared_mutex shared/write lock" << std::endl;
{
booster::mutex fm;
booster::shared_mutex sm;
@@ -312,9 +324,45 @@ int main()
bool mread_happened = false;
bool write_happened = false;
bool error_occured = false ;
rw_executor exec1 = { flags + 0, true, &fm, &sm };
rw_executor exec2 = { flags + 1, true, &fm, &sm };
rw_executor exec3 = { flags + 2, true, &fm, &sm };
rw_executor<booster::shared_mutex> exec1 = { flags + 0, true, &fm, &sm };
rw_executor<booster::shared_mutex> exec2 = { flags + 1, true, &fm, &sm };
rw_executor<booster::shared_mutex> exec3 = { flags + 2, true, &fm, &sm };
booster::thread t1(exec1);
booster::thread t2(exec2);
booster::thread t3(exec3);

for(int i=0;i<100;i++) {
booster::ptime::millisleep(1);
{
booster::unique_lock<booster::mutex> l(fm);
if(flags[0] && flags[1])
mread_happened = true;
if(flags[2])
write_happened = true;
if((flags[0] || flags[1]) && flags[2])
error_occured = true;
}
}

t1.join();
t2.join();
t3.join();

TEST(mread_happened);
TEST(write_happened);
TEST(error_occured);
}
std::cout << "Test recursive_shared_mutex shared/write lock" << std::endl;
{
booster::mutex fm;
booster::recursive_shared_mutex sm;
bool flags[3] = {false,false,false};
bool mread_happened = false;
bool write_happened = false;
bool error_occured = false ;
rw_executor<booster::recursive_shared_mutex> exec1 = { flags + 0, true, &fm, &sm };
rw_executor<booster::recursive_shared_mutex> exec2 = { flags + 1, true, &fm, &sm };
rw_executor<booster::recursive_shared_mutex> exec3 = { flags + 2, true, &fm, &sm };
booster::thread t1(exec1);
booster::thread t2(exec2);
booster::thread t3(exec3);
@@ -340,9 +388,9 @@ int main()
TEST(write_happened);
TEST(error_occured);
}
std::cout << "Test rw_lock recursive shared lock" << std::endl;
std::cout << "Test recursive_shared_mutex recursive shared lock" << std::endl;
{
booster::shared_mutex l;
booster::recursive_shared_mutex l;
bool read = false;
bool write = false;
rw_shared_thread t1c = { &l, &read };


+ 8
- 8
src/views_pool.cpp View File

@@ -68,7 +68,7 @@ std::auto_ptr<base_view> generator::create( std::string const &view_name,

// class pool
struct pool::data {
booster::shared_mutex lock;
booster::recursive_shared_mutex lock;
typedef std::map<std::string,generator const *> generators_type;
generators_type generators;
};
@@ -78,7 +78,7 @@ void pool::add(generator const &g)
generator const *ptr = &g;
std::string name = ptr->name();

booster::unique_lock<booster::shared_mutex> guard(d->lock);
booster::unique_lock<booster::recursive_shared_mutex> guard(d->lock);
for(data::generators_type::iterator p=d->generators.begin();p!=d->generators.end();++p) {
if(p->second == ptr)
return;
@@ -92,7 +92,7 @@ void pool::remove(generator const &g)
{
generator const *ptr = &g;

booster::unique_lock<booster::shared_mutex> guard(d->lock);
booster::unique_lock<booster::recursive_shared_mutex> guard(d->lock);
for(data::generators_type::iterator p=d->generators.begin();p!=d->generators.end();++p) {
if(p->second == ptr) {
d->generators.erase(p);
@@ -103,7 +103,7 @@ void pool::remove(generator const &g)

void pool::render(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content)
{
booster::shared_lock<booster::shared_mutex> guard(d->lock);
booster::shared_lock<booster::recursive_shared_mutex> guard(d->lock);
data::generators_type::iterator p=d->generators.find(skin);
if(p==d->generators.end())
throw cppcms_error("cppcms::views::pool: no such skin:" + skin);
@@ -118,7 +118,7 @@ void pool::render(std::string const &skin,std::string const &template_name,std::

std::vector<std::string> pool::enumerate()
{
booster::shared_lock<booster::shared_mutex> guard(d->lock);
booster::shared_lock<booster::recursive_shared_mutex> guard(d->lock);
std::vector<std::string> all;
all.reserve(d->generators.size());
for(data::generators_type::iterator p=d->generators.begin(),e=d->generators.end();p!=e;++p) {
@@ -254,7 +254,7 @@ struct manager::data {
bool auto_reload;
std::string default_skin;
std::vector<impl::skin> skins;
booster::shared_mutex lock;
booster::recursive_shared_mutex lock;
data() : auto_reload(false)
{
}
@@ -320,7 +320,7 @@ void manager::render(std::string const &skin_name,std::string const &template_na
if(d->auto_reload) {
{ // Check if update
bool reload_required = false;
booster::shared_lock<booster::shared_mutex> guard(d->lock);
booster::shared_lock<booster::recursive_shared_mutex> guard(d->lock);
for(size_t i=0;i<d->skins.size();i++) {
time_t mtime = impl::get_mtime(d->skins[i].file_name);
if(mtime != d->skins[i].mtime) {
@@ -334,7 +334,7 @@ void manager::render(std::string const &skin_name,std::string const &template_na
}
}
// reload all if needed
booster::unique_lock<booster::shared_mutex> lock(d->lock);
booster::unique_lock<booster::recursive_shared_mutex> lock(d->lock);
for(size_t i=0;i<d->skins.size();i++) {
impl::skin &current = d->skins[i];
time_t mtime = impl::get_mtime(current.file_name);


Loading…
Cancel
Save