实现condition_win

This commit is contained in:
mutouyun 2021-09-19 22:26:32 +08:00
parent 0cccdac868
commit c1ceaa657a
3 changed files with 84 additions and 17 deletions

View File

@ -1,52 +1,116 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <string>
#include <mutex>
#include <Windows.h> #include <Windows.h>
#include "libipc/utility/log.h" #include "libipc/utility/log.h"
#include "libipc/utility/scope_guard.h"
#include "libipc/platform/detail.h"
#include "libipc/mutex.h" #include "libipc/mutex.h"
#include "libipc/semaphore.h"
#include "libipc/shm.h"
namespace ipc { namespace ipc {
namespace detail { namespace detail {
namespace sync { namespace sync {
class condition { class condition {
HANDLE h_ = NULL; ipc::sync::semaphore sem_;
ipc::sync::mutex lock_;
ipc::shm::handle shm_;
std::int32_t &counter() {
return *static_cast<std::int32_t *>(shm_.get());
}
public: public:
condition() noexcept = default; condition() = default;
~condition() noexcept = default; ~condition() noexcept = default;
HANDLE native() const noexcept { auto native() noexcept {
return h_; return sem_.native();
}
auto native() const noexcept {
return sem_.native();
} }
bool valid() const noexcept { bool valid() const noexcept {
return h_ != NULL; return sem_.valid() && lock_.valid() && shm_.valid();
} }
bool open(char const *name) noexcept { bool open(char const *name) noexcept {
close(); close();
if (!sem_.open((std::string{"_cond_sem_"} + name).c_str())) {
return false;
}
auto finally_sem = ipc::guard([this] { sem_.close(); }); // close when failed
if (!lock_.open((std::string{"_cond_lock_"} + name).c_str())) {
return false;
}
auto finally_lock = ipc::guard([this] { lock_.close(); }); // close when failed
if (!shm_.acquire((std::string{"_cond_shm_"} + name).c_str(), sizeof(std::int32_t))) {
return false;
}
finally_lock.dismiss();
finally_sem.dismiss();
return valid(); return valid();
} }
void close() noexcept { void close() noexcept {
if (!valid()) return; if (!valid()) return;
::CloseHandle(h_); sem_.close();
h_ = NULL; lock_.close();
shm_.release();
} }
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept { bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
return true; if (!valid()) return false;
auto &cnt = counter();
{
IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
cnt = (cnt < 0) ? 1 : cnt + 1;
}
DWORD ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
/**
* @see
* - https://www.microsoft.com/en-us/research/wp-content/uploads/2004/12/ImplementingCVs.pdf
* - https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-signalobjectandwait
*/
bool rs = ::SignalObjectAndWait(mtx.native(), sem_.native(), ms, FALSE) == WAIT_OBJECT_0;
bool rl = mtx.lock(); // INFINITE
if (!rs) {
IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
cnt -= 1;
}
return rs && rl;
} }
bool notify() noexcept { bool notify() noexcept {
return true; if (!valid()) return false;
auto &cnt = counter();
if (!lock_.lock()) return false;
bool ret = false;
if (cnt > 0) {
ret = sem_.post(1);
cnt -= 1;
}
return lock_.unlock() && ret;
} }
bool broadcast() noexcept { bool broadcast() noexcept {
return true; if (!valid()) return false;
auto &cnt = counter();
if (!lock_.lock()) return false;
bool ret = false;
if (cnt > 0) {
ret = sem_.post(cnt);
cnt = 0;
}
return lock_.unlock() && ret;
} }
}; };

View File

@ -41,7 +41,7 @@ constexpr auto to_tchar(ipc::string &&str) -> IsSameChar<T, ipc::string, ipc::st
} }
/** /**
* codecvt_utf8_utf16/std::wstring_convert is deprecated * @remarks codecvt_utf8_utf16/std::wstring_convert is deprecated
* @see https://codingtidbit.com/2020/02/09/c17-codecvt_utf8-is-deprecated/ * @see https://codingtidbit.com/2020/02/09/c17-codecvt_utf8-is-deprecated/
* https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement * https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement
* https://en.cppreference.com/w/cpp/locale/codecvt/in * https://en.cppreference.com/w/cpp/locale/codecvt/in

View File

@ -4,6 +4,7 @@
#include <mutex> #include <mutex>
#include <chrono> #include <chrono>
#include <deque> #include <deque>
#include <array>
#include <cstdio> #include <cstdio>
#include "test.h" #include "test.h"
@ -129,8 +130,10 @@ TEST(Sync, Condition) {
std::printf("test-cond-%d: %d\n", num, val); std::printf("test-cond-%d: %d\n", num, val);
} }
}; };
std::thread test_cond1 {job, 1}; std::array<std::thread, 10> test_conds;
std::thread test_cond2 {job, 2}; for (int i = 0; i < (int)test_conds.size(); ++i) {
test_conds[i] = std::thread{job, i};
}
for (int i = 1; i < 100; ++i) { for (int i = 1; i < 100; ++i) {
{ {
@ -150,11 +153,11 @@ TEST(Sync, Condition) {
} }
{ {
std::lock_guard<ipc::sync::mutex> guard {lock}; std::lock_guard<ipc::sync::mutex> guard {lock};
for (int i = 0; i < (int)test_conds.size(); ++i) {
que.push_back(0); que.push_back(0);
que.push_back(0); }
} }
cond.broadcast(); cond.broadcast();
test_cond1.join(); for (auto &t : test_conds) t.join();
test_cond2.join();
} }