impl condition for windows

This commit is contained in:
mutouyun 2019-02-14 14:11:03 +08:00
parent 75f5090d6a
commit dd80a79c3c
2 changed files with 104 additions and 50 deletions

View File

@ -62,7 +62,7 @@ public:
}; };
class condition { class condition {
pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_ = PTHREAD_COND_INITIALIZER;
public: public:
bool open() { bool open() {
@ -163,8 +163,8 @@ public:
} }
void close(handle_t h) { void close(handle_t h) {
if (h == invalid()) return;
if (opened_.fetch_sub(1, std::memory_order_release) == 1) { if (opened_.fetch_sub(1, std::memory_order_release) == 1) {
if (h == invalid()) return;
sem_.close(); sem_.close();
} }
} }

View File

@ -7,6 +7,7 @@
#include "rw_lock.h" #include "rw_lock.h"
#include "pool_alloc.h" #include "pool_alloc.h"
#include "log.h"
#include "platform/to_tchar.h" #include "platform/to_tchar.h"
#include "platform/detail.h" #include "platform/detail.h"
@ -22,10 +23,13 @@ public:
return s1.h_ == s2.h_; return s1.h_ == s2.h_;
} }
template <typename Str> bool open(std::string && name, long count = 0, long limit = LONG_MAX) {
semaphore& open(Str const & name, long count = 0, long limit = LONG_MAX) { h_ = ::CreateSemaphore(NULL, count, limit, ipc::detail::to_tchar(std::move(name)).c_str());
h_ = ::CreateSemaphore(NULL, count, limit, name.c_str()); if (h_ == NULL) {
return *this; ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name.c_str());
return false;
}
return true;
} }
void close() { void close() {
@ -46,82 +50,132 @@ class mutex : public semaphore {
using semaphore::post; using semaphore::post;
public: public:
template <typename Str> bool open(std::string && name) {
mutex& open(Str const & name) { return semaphore::open(std::move(name), 1, 1);
semaphore::open(name, 1, 1);
return *this;
} }
bool lock () { return semaphore::wait(); } bool lock () { return semaphore::wait(); }
bool unlock() { return semaphore::post(); } bool unlock() { return semaphore::post(); }
}; };
class condition {
mutex lock_;
semaphore sema_, handshake_;
long volatile * counter_ = nullptr;
public:
friend bool operator==(condition const & c1, condition const & c2) {
return c1.counter_ == c2.counter_;
}
friend bool operator!=(condition const & c1, condition const & c2) {
return !(c1 == c2);
}
bool open(std::string const & name, long volatile * counter) {
if (lock_ .open(name + "__COND_MTX__") &&
sema_ .open(name + "__COND_SEM__") &&
handshake_.open(name + "__COND_HAN__")) {
counter_ = counter;
return true;
}
return false;
}
void close() {
handshake_.close();
sema_ .close();
lock_ .close();
}
template <typename Mutex, typename F>
bool wait_if(Mutex& mtx, F&& pred) {
{
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lock_);
if (!std::forward<F>(pred)()) return true;
++ *counter_;
}
mtx.unlock();
bool ret_s = sema_.wait();
bool ret_h = handshake_.post();
mtx.lock();
return ret_s && ret_h;
}
bool notify() {
bool ret_s = true, ret_h = true;
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lock_);
if (*counter_ > 0) {
ret_s = sema_.post();
-- *counter_;
ret_h = handshake_.wait();
}
return ret_s && ret_h;
}
bool broadcast() {
bool ret_s = true, ret_h = true;
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lock_);
if (*counter_ > 0) {
ret_s = sema_.post(*counter_);
do {
-- *counter_;
bool rh = handshake_.wait();
ret_h = ret_h && rh;
} while (*counter_ > 0);
}
return ret_s && ret_h;
}
};
class waiter { class waiter {
long volatile counter_ = 0; long volatile counter_ = 0;
public: public:
using handle_t = std::tuple<semaphore, semaphore, mutex>; using handle_t = condition;
static handle_t invalid() { static handle_t invalid() {
return handle_t {}; return condition {};
} }
private:
semaphore& sem(handle_t& h) { return std::get<0>(h); }
semaphore& han(handle_t& h) { return std::get<1>(h); }
mutex & mtx(handle_t& h) { return std::get<2>(h); }
public:
handle_t open(char const * name) { handle_t open(char const * name) {
if (name == nullptr || name[0] == '\0') return invalid(); if (name == nullptr || name[0] == '\0') {
std::string n = name; return invalid();
return handle_t { }
semaphore {}.open(ipc::detail::to_tchar(n + "__SEM__")), condition cond;
semaphore {}.open(ipc::detail::to_tchar(n + "__HAN__")), if (cond.open(name, &counter_)) {
mutex {}.open(ipc::detail::to_tchar(n + "__MTX__")) return cond;
}; }
return invalid();
} }
void close(handle_t& h) { void close(handle_t& h) {
if (h == invalid()) return; if (h == invalid()) return;
mtx(h).close(); h.close();
han(h).close();
sem(h).close();
} }
template <typename F> template <typename F>
bool wait_if(handle_t& h, F&& pred) { bool wait_if(handle_t& h, F&& pred) {
if (h == invalid()) return false; if (h == invalid()) return false;
{
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(mtx(h)); class non_mutex {
if (!std::forward<F>(pred)()) return true; public:
++ counter_; void lock () {}
} void unlock() {}
bool ret_s = sem(h).wait(); } nm;
bool ret_h = han(h).post();
return ret_s && ret_h; return h.wait_if(nm, std::forward<F>(pred));
} }
void notify(handle_t& h) { void notify(handle_t& h) {
if (h == invalid()) return; if (h == invalid()) return;
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(mtx(h)); h.notify();
if (counter_ > 0) {
sem(h).post();
-- counter_;
han(h).wait();
}
} }
void broadcast(handle_t& h) { void broadcast(handle_t& h) {
if (h == invalid()) return; if (h == invalid()) return;
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(mtx(h)); h.broadcast();
if (counter_ > 0) {
sem(h).post(counter_);
do {
-- counter_;
han(h).wait();
} while (counter_ > 0);
}
} }
}; };