Skip to content

Commit c1ceaa6

Browse files
committed
实现condition_win
1 parent 0cccdac commit c1ceaa6

File tree

3 files changed

+84
-17
lines changed

3 files changed

+84
-17
lines changed

src/libipc/platform/condition_win.h

Lines changed: 74 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,116 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <string>
5+
#include <mutex>
46

57
#include <Windows.h>
68

79
#include "libipc/utility/log.h"
10+
#include "libipc/utility/scope_guard.h"
11+
#include "libipc/platform/detail.h"
812
#include "libipc/mutex.h"
13+
#include "libipc/semaphore.h"
14+
#include "libipc/shm.h"
915

1016
namespace ipc {
1117
namespace detail {
1218
namespace sync {
1319

1420
class condition {
15-
HANDLE h_ = NULL;
21+
ipc::sync::semaphore sem_;
22+
ipc::sync::mutex lock_;
23+
ipc::shm::handle shm_;
24+
25+
std::int32_t &counter() {
26+
return *static_cast<std::int32_t *>(shm_.get());
27+
}
1628

1729
public:
18-
condition() noexcept = default;
30+
condition() = default;
1931
~condition() noexcept = default;
2032

21-
HANDLE native() const noexcept {
22-
return h_;
33+
auto native() noexcept {
34+
return sem_.native();
35+
}
36+
37+
auto native() const noexcept {
38+
return sem_.native();
2339
}
2440

2541
bool valid() const noexcept {
26-
return h_ != NULL;
42+
return sem_.valid() && lock_.valid() && shm_.valid();
2743
}
2844

2945
bool open(char const *name) noexcept {
3046
close();
47+
if (!sem_.open((std::string{"_cond_sem_"} + name).c_str())) {
48+
return false;
49+
}
50+
auto finally_sem = ipc::guard([this] { sem_.close(); }); // close when failed
51+
if (!lock_.open((std::string{"_cond_lock_"} + name).c_str())) {
52+
return false;
53+
}
54+
auto finally_lock = ipc::guard([this] { lock_.close(); }); // close when failed
55+
if (!shm_.acquire((std::string{"_cond_shm_"} + name).c_str(), sizeof(std::int32_t))) {
56+
return false;
57+
}
58+
finally_lock.dismiss();
59+
finally_sem.dismiss();
3160
return valid();
3261
}
3362

3463
void close() noexcept {
3564
if (!valid()) return;
36-
::CloseHandle(h_);
37-
h_ = NULL;
65+
sem_.close();
66+
lock_.close();
67+
shm_.release();
3868
}
3969

4070
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
41-
return true;
71+
if (!valid()) return false;
72+
auto &cnt = counter();
73+
{
74+
IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
75+
cnt = (cnt < 0) ? 1 : cnt + 1;
76+
}
77+
DWORD ms = (tm == invalid_value) ? INFINITE : static_cast<DWORD>(tm);
78+
/**
79+
* @see
80+
* - https://www.microsoft.com/en-us/research/wp-content/uploads/2004/12/ImplementingCVs.pdf
81+
* - https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-signalobjectandwait
82+
*/
83+
bool rs = ::SignalObjectAndWait(mtx.native(), sem_.native(), ms, FALSE) == WAIT_OBJECT_0;
84+
bool rl = mtx.lock(); // INFINITE
85+
if (!rs) {
86+
IPC_UNUSED_ std::lock_guard<ipc::sync::mutex> guard {lock_};
87+
cnt -= 1;
88+
}
89+
return rs && rl;
4290
}
4391

4492
bool notify() noexcept {
45-
return true;
93+
if (!valid()) return false;
94+
auto &cnt = counter();
95+
if (!lock_.lock()) return false;
96+
bool ret = false;
97+
if (cnt > 0) {
98+
ret = sem_.post(1);
99+
cnt -= 1;
100+
}
101+
return lock_.unlock() && ret;
46102
}
47103

48104
bool broadcast() noexcept {
49-
return true;
105+
if (!valid()) return false;
106+
auto &cnt = counter();
107+
if (!lock_.lock()) return false;
108+
bool ret = false;
109+
if (cnt > 0) {
110+
ret = sem_.post(cnt);
111+
cnt = 0;
112+
}
113+
return lock_.unlock() && ret;
50114
}
51115
};
52116

src/libipc/platform/to_tchar.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ constexpr auto to_tchar(ipc::string &&str) -> IsSameChar<T, ipc::string, ipc::st
4141
}
4242

4343
/**
44-
* codecvt_utf8_utf16/std::wstring_convert is deprecated
44+
* @remarks codecvt_utf8_utf16/std::wstring_convert is deprecated
4545
* @see https://codingtidbit.com/2020/02/09/c17-codecvt_utf8-is-deprecated/
4646
* https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement
4747
* https://en.cppreference.com/w/cpp/locale/codecvt/in

test/test_sync.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <mutex>
55
#include <chrono>
66
#include <deque>
7+
#include <array>
78
#include <cstdio>
89

910
#include "test.h"
@@ -129,8 +130,10 @@ TEST(Sync, Condition) {
129130
std::printf("test-cond-%d: %d\n", num, val);
130131
}
131132
};
132-
std::thread test_cond1 {job, 1};
133-
std::thread test_cond2 {job, 2};
133+
std::array<std::thread, 10> test_conds;
134+
for (int i = 0; i < (int)test_conds.size(); ++i) {
135+
test_conds[i] = std::thread{job, i};
136+
}
134137

135138
for (int i = 1; i < 100; ++i) {
136139
{
@@ -150,11 +153,11 @@ TEST(Sync, Condition) {
150153
}
151154
{
152155
std::lock_guard<ipc::sync::mutex> guard {lock};
153-
que.push_back(0);
154-
que.push_back(0);
156+
for (int i = 0; i < (int)test_conds.size(); ++i) {
157+
que.push_back(0);
158+
}
155159
}
156160
cond.broadcast();
157161

158-
test_cond1.join();
159-
test_cond2.join();
162+
for (auto &t : test_conds) t.join();
160163
}

0 commit comments

Comments
 (0)