fix bugs of windows-waiter

This commit is contained in:
mutouyun 2019-02-13 06:45:41 +08:00
parent a6d88a1208
commit cee63e5f81
3 changed files with 90 additions and 31 deletions

View File

@ -30,7 +30,8 @@ Performance data: [performence.xlsx](performence.xlsx)
## Reference ## Reference
* [http://www.drdobbs.com/lock-free-data-structures/184401865](http://www.drdobbs.com/lock-free-data-structures/184401865) * [Lock-Free Data Structures | Dr Dobb's](http://www.drdobbs.com/lock-free-data-structures/184401865)
* [https://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular](https://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular) * [Yet another implementation of a lock-free circular array queue | CodeProject](https://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular)
* [http://www.cnblogs.com/gaochundong/p/lock_free_programming.html](http://www.cnblogs.com/gaochundong/p/lock_free_programming.html) * [Lock-Free 编程 | 匠心十年 - 博客园](http://www.cnblogs.com/gaochundong/p/lock_free_programming.html)
* [https://coolshell.cn/articles/8239.html](https://coolshell.cn/articles/8239.html) * [无锁队列的实现 | 酷 壳 - CoolShell](https://coolshell.cn/articles/8239.html)
* [Implementing Condition Variables with Semaphores](https://www.microsoft.com/en-us/research/wp-content/uploads/2004/12/ImplementingCVs.pdf)

View File

@ -3,6 +3,7 @@
#include <Windows.h> #include <Windows.h>
#include <atomic> #include <atomic>
#include <tuple>
#include "rw_lock.h" #include "rw_lock.h"
#include "pool_alloc.h" #include "pool_alloc.h"
@ -13,59 +14,112 @@
namespace ipc { namespace ipc {
namespace detail { namespace detail {
class waiter { class semaphore {
long volatile counter_ = 0; HANDLE h_ = NULL;
spin_lock lock_;
public: public:
using handle_t = HANDLE; friend bool operator==(semaphore const & s1, semaphore const & s2) {
return s1.h_ == s2.h_;
constexpr static handle_t invalid() {
return NULL;
} }
template <typename Str>
semaphore& open(Str const & name, long count = 0, long limit = LONG_MAX) {
h_ = ::CreateSemaphore(NULL, count, limit, name.c_str());
return *this;
}
void close() {
::CloseHandle(h_);
}
bool wait() {
return ::WaitForSingleObject(h_, INFINITE) == WAIT_OBJECT_0;
}
bool post(long count = 1) {
if (count <= 0) return true;
return !!::ReleaseSemaphore(h_, count, NULL);
}
};
class mutex : public semaphore {
using semaphore::wait;
using semaphore::post;
public:
template <typename Str>
mutex& open(Str const & name) {
semaphore::open(name, 1, 1);
return *this;
}
bool lock () { return semaphore::wait(); }
bool unlock() { return semaphore::post(); }
};
class waiter {
long volatile counter_ = 0;
public:
using handle_t = std::tuple<semaphore, semaphore, mutex>;
static handle_t invalid() {
return handle_t {};
}
private:
semaphore& s(handle_t& h) { return std::get<0>(h); }
semaphore& w(handle_t& h) { return std::get<1>(h); }
mutex & x(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') return invalid();
return ::CreateSemaphore(NULL, 0, LONG_MAX, ipc::detail::to_tchar(name).c_str()); std::string n = name;
return handle_t {
semaphore {}.open(ipc::detail::to_tchar(n + "__S__")),
semaphore {}.open(ipc::detail::to_tchar(n + "__W__")),
mutex {}.open(ipc::detail::to_tchar(n + "__X__"))
};
} }
void close(handle_t h) { void close(handle_t& h) {
if (h == invalid()) return; if (h == invalid()) return;
::CloseHandle(h); x(h).close();
w(h).close();
s(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(lock_); IPC_UNUSED_ auto guard = ipc::detail::unique_lock(x(h));
if (!std::forward<F>(pred)()) return true; if (!std::forward<F>(pred)()) return true;
++ counter_; ++ counter_;
} }
return ::WaitForSingleObject(h, INFINITE) == WAIT_OBJECT_0; if (!s(h).wait()) return false;
return w(h).post();
} }
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(x(h));
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lock_); if (counter_ > 0) {
if (counter_ == 0) return; s(h).post();
-- counter_; -- counter_;
::ReleaseSemaphore(h, 1, NULL); w(h).wait();
} }
::Sleep(1);
} }
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(x(h));
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(lock_); s(h).post(counter_);
if (counter_ == 0) return; while (counter_ > 0) {
long all_count = counter_; -- counter_;
counter_ = 0; w(h).wait();
::ReleaseSemaphore(h, all_count, NULL);
} }
::Sleep(1);
} }
}; };

View File

@ -323,6 +323,7 @@ void test_prod_cons() {
} }
void Unit::test_route() { void Unit::test_route() {
//return;
std::vector<char const *> const datas = { std::vector<char const *> const datas = {
"hello!", "hello!",
"foo", "foo",
@ -360,6 +361,7 @@ void Unit::test_route() {
} }
void Unit::test_route_rtt() { void Unit::test_route_rtt() {
//return;
test_stopwatch sw; test_stopwatch sw;
std::thread t1 {[&] { std::thread t1 {[&] {
@ -399,6 +401,7 @@ void Unit::test_route_rtt() {
} }
void Unit::test_route_performance() { void Unit::test_route_performance() {
//return;
ipc::detail::static_for(std::make_index_sequence<8>{}, [](auto index) { ipc::detail::static_for(std::make_index_sequence<8>{}, [](auto index) {
test_prod_cons<ipc::route, 1, decltype(index)::value + 1, false>(); test_prod_cons<ipc::route, 1, decltype(index)::value + 1, false>();
}); });
@ -406,6 +409,7 @@ void Unit::test_route_performance() {
} }
void Unit::test_channel() { void Unit::test_channel() {
//return;
std::thread t1 {[&] { std::thread t1 {[&] {
ipc::channel cc { "my-ipc-channel" }; ipc::channel cc { "my-ipc-channel" };
for (std::size_t i = 0;; ++i) { for (std::size_t i = 0;; ++i) {