Skip to content

Commit 0cea895

Browse files
author
test
committed
v2.1 Merge branch 'dev': Channel的超时从忙轮询改为定时器
2 parents b362d1e + 2e9e59d commit 0cea895

File tree

11 files changed

+349
-147
lines changed

11 files changed

+349
-147
lines changed

src/block_object.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,47 @@ void BlockObject::CoBlockWait()
3636
--wakeup_;
3737
return ;
3838
}
39+
lock.unlock();
3940

4041
Task* tk = g_Scheduler.GetLocalInfo().current_task;
4142
tk->block_ = this;
4243
tk->state_ = TaskState::sys_block;
44+
tk->block_timeout_ = std::chrono::nanoseconds::zero();
45+
tk->is_block_timeout_ = false;
46+
++ tk->block_sequence_;
47+
DebugPrint(dbg_syncblock, "wait to switch. task(%s)", tk->DebugInfo());
48+
g_Scheduler.CoYield();
49+
}
50+
51+
bool BlockObject::CoBlockWaitTimed(std::chrono::nanoseconds timeo)
52+
{
53+
auto begin = std::chrono::high_resolution_clock::now();
54+
if (!g_Scheduler.IsCoroutine()) {
55+
while (!TryBlockWait() &&
56+
std::chrono::duration_cast<std::chrono::nanoseconds>
57+
(std::chrono::high_resolution_clock::now() - begin) < timeo)
58+
usleep(10 * 1000);
59+
return false;
60+
}
61+
62+
std::unique_lock<LFLock> lock(lock_);
63+
if (wakeup_ > 0) {
64+
DebugPrint(dbg_syncblock, "wait immedaitely done.");
65+
--wakeup_;
66+
return true;
67+
}
4368
lock.unlock();
69+
70+
Task* tk = g_Scheduler.GetLocalInfo().current_task;
71+
tk->block_ = this;
72+
tk->state_ = TaskState::sys_block;
73+
++tk->block_sequence_;
74+
tk->block_timeout_ = timeo;
75+
tk->is_block_timeout_ = false;
4476
DebugPrint(dbg_syncblock, "wait to switch. task(%s)", tk->DebugInfo());
4577
g_Scheduler.CoYield();
78+
79+
return !tk->is_block_timeout_;
4680
}
4781

4882
bool BlockObject::TryBlockWait()
@@ -71,10 +105,35 @@ bool BlockObject::Wakeup()
71105
return true;
72106
}
73107

108+
tk->block_ = nullptr;
74109
g_Scheduler.AddTaskRunnable(tk);
75110
DebugPrint(dbg_syncblock, "wakeup task(%s).", tk->DebugInfo());
76111
return true;
77112
}
113+
void BlockObject::CancelWait(Task* tk, uint32_t block_sequence)
114+
{
115+
std::unique_lock<LFLock> lock(lock_);
116+
if (tk->block_ != this) {
117+
DebugPrint(dbg_syncblock, "cancelwait task(%s) failed. tk->block_ is not this!", tk->DebugInfo());
118+
return;
119+
}
120+
121+
if (tk->block_sequence_ != block_sequence) {
122+
DebugPrint(dbg_syncblock, "cancelwait task(%s) failed. tk->block_sequence_ = %u, block_sequence = %u.",
123+
tk->DebugInfo(), tk->block_sequence_, block_sequence);
124+
return;
125+
}
126+
127+
if (!wait_queue_.erase(tk)) {
128+
DebugPrint(dbg_syncblock, "cancelwait task(%s) erase failed.", tk->DebugInfo());
129+
return;
130+
}
131+
132+
tk->block_ = nullptr;
133+
tk->is_block_timeout_ = true;
134+
g_Scheduler.AddTaskRunnable(tk);
135+
DebugPrint(dbg_syncblock, "cancelwait task(%s).", tk->DebugInfo());
136+
}
78137

79138
bool BlockObject::IsWakeup()
80139
{
@@ -91,6 +150,20 @@ bool BlockObject::AddWaitTask(Task* tk)
91150
}
92151

93152
wait_queue_.push(tk);
153+
154+
// 带超时的, 增加定时器
155+
if (std::chrono::nanoseconds::zero() != tk->block_timeout_) {
156+
uint32_t seq = tk->block_sequence_;
157+
tk->IncrementRef();
158+
lock.unlock(); // sequence记录完成, task引用计数增加, 可以解锁了
159+
160+
g_Scheduler.ExpireAt(tk->block_timeout_, [=]{
161+
if (tk->block_sequence_ == seq)
162+
this->CancelWait(tk, seq);
163+
tk->DecrementRef();
164+
});
165+
}
166+
94167
return true;
95168
}
96169

src/block_object.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,37 @@
55
namespace co
66
{
77

8+
// 信号管理对象
9+
// @线程安全
810
class BlockObject
911
{
1012
protected:
1113
friend class Processer;
12-
std::size_t wakeup_;
13-
std::size_t max_wakeup_;
14-
TSQueue<Task, false> wait_queue_;
14+
std::size_t wakeup_; // 当前信号数量
15+
std::size_t max_wakeup_; // 可以积累的信号数量上限
16+
TSQueue<Task, false> wait_queue_; // 等待信号的协程队列
1517
LFLock lock_;
1618

1719
public:
1820
explicit BlockObject(std::size_t init_wakeup = 0, std::size_t max_wakeup = -1);
1921
~BlockObject();
2022

23+
// 阻塞式等待信号
2124
void CoBlockWait();
2225

26+
// 带超时的阻塞式等待信号
27+
// @returns: 是否成功等到信号
28+
bool CoBlockWaitTimed(std::chrono::nanoseconds timeo);
29+
2330
bool TryBlockWait();
2431

2532
bool Wakeup();
2633

2734
bool IsWakeup();
2835

2936
private:
37+
void CancelWait(Task* tk, uint32_t block_sequence);
38+
3039
bool AddWaitTask(Task* tk);
3140
};
3241

src/channel.h

Lines changed: 109 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -62,54 +62,21 @@ class Channel
6262
}
6363

6464
template <typename U, typename Duration>
65-
bool BlockTryPush(U && t, Duration const& timeout) const
65+
bool TimedPush(U && t, Duration const& timeout) const
6666
{
67-
int interval = 1;
68-
auto begin = std::chrono::high_resolution_clock::now();
69-
while (!TryPush(std::forward<U>(t))) {
70-
auto now = std::chrono::high_resolution_clock::now();
71-
if (std::chrono::duration_cast<Duration>(now - begin) >= timeout)
72-
return false;
73-
74-
interval = std::min(32, interval << 1);
75-
g_Scheduler.SleepSwitch(interval);
76-
}
77-
78-
return true;
67+
return impl_->TimedPush(std::forward<U>(t), timeout);
7968
}
8069

8170
template <typename U, typename Duration>
82-
bool BlockTryPop(U & t, Duration const& timeout) const
71+
bool TimedPop(U & t, Duration const& timeout) const
8372
{
84-
int interval = 1;
85-
auto begin = std::chrono::high_resolution_clock::now();
86-
while (!TryPop(t)) {
87-
auto now = std::chrono::high_resolution_clock::now();
88-
if (std::chrono::duration_cast<Duration>(now - begin) >= timeout)
89-
return false;
90-
91-
interval = std::min(32, interval << 1);
92-
g_Scheduler.SleepSwitch(interval);
93-
}
94-
95-
return true;
73+
return impl_->TimedPop(t, timeout);
9674
}
9775

9876
template <typename Duration>
99-
bool BlockTryPop(nullptr_t ignore, Duration const& timeout) const
77+
bool TimedPop(nullptr_t ignore, Duration const& timeout) const
10078
{
101-
int interval = 1;
102-
auto begin = std::chrono::high_resolution_clock::now();
103-
while (!TryPop(ignore)) {
104-
auto now = std::chrono::high_resolution_clock::now();
105-
if (std::chrono::duration_cast<Duration>(now - begin) >= timeout)
106-
return false;
107-
108-
interval = std::min(32, interval << 1);
109-
g_Scheduler.SleepSwitch(interval);
110-
}
111-
112-
return true;
79+
return impl_->TimedPop(ignore, timeout);
11380
}
11481

11582
bool Unique() const
@@ -170,6 +137,72 @@ class Channel
170137
}
171138
}
172139

140+
// write
141+
template <typename U, typename Duration>
142+
bool TimedPush(U && t, Duration const& dur)
143+
{
144+
if (!write_block_.CoBlockWaitTimed(std::chrono::duration_cast<std::chrono::nanoseconds>(dur)))
145+
return false;
146+
147+
{
148+
std::unique_lock<CoMutex> lock(queue_lock_);
149+
queue_.push(std::forward<U>(t));
150+
}
151+
152+
read_block_.Wakeup();
153+
return true;
154+
}
155+
156+
// read
157+
template <typename U, typename Duration>
158+
bool TimedPop(U & t, Duration const& dur)
159+
{
160+
write_block_.Wakeup();
161+
if (!read_block_.CoBlockWaitTimed(std::chrono::duration_cast<std::chrono::nanoseconds>(dur)))
162+
{
163+
if (write_block_.TryBlockWait())
164+
return false;
165+
else
166+
{
167+
while (!read_block_.TryBlockWait())
168+
if (write_block_.TryBlockWait())
169+
return false;
170+
else
171+
g_Scheduler.CoYield();
172+
}
173+
}
174+
175+
std::unique_lock<CoMutex> lock(queue_lock_);
176+
t = std::move(queue_.front());
177+
queue_.pop();
178+
return true;
179+
}
180+
181+
// read and ignore
182+
template <typename Duration>
183+
bool TimedPop(nullptr_t ignore, Duration const& dur)
184+
{
185+
write_block_.Wakeup();
186+
if (!read_block_.CoBlockWaitTimed(std::chrono::duration_cast<std::chrono::nanoseconds>(dur)))
187+
{
188+
if (write_block_.TryBlockWait())
189+
return false;
190+
else
191+
{
192+
while (!read_block_.TryBlockWait())
193+
if (write_block_.TryBlockWait())
194+
return false;
195+
else
196+
g_Scheduler.CoYield();
197+
}
198+
}
199+
200+
std::unique_lock<CoMutex> lock(queue_lock_);
201+
queue_.pop();
202+
return true;
203+
}
204+
205+
173206
// try write
174207
template <typename U>
175208
bool TryPush(U && t)
@@ -266,37 +299,15 @@ class Channel<void>
266299
}
267300

268301
template <typename Duration>
269-
bool BlockTryPush(nullptr_t ignore, Duration const& timeout) const
302+
bool TimedPush(nullptr_t ignore, Duration const& timeout) const
270303
{
271-
int interval = 1;
272-
auto begin = std::chrono::high_resolution_clock::now();
273-
while (!TryPush(ignore)) {
274-
auto now = std::chrono::high_resolution_clock::now();
275-
if (std::chrono::duration_cast<Duration>(now - begin) >= timeout)
276-
return false;
277-
278-
interval = std::min(32, interval << 1);
279-
g_Scheduler.SleepSwitch(interval);
280-
}
281-
282-
return true;
304+
return impl_->TimedPush(ignore, timeout);
283305
}
284306

285307
template <typename Duration>
286-
bool BlockTryPop(nullptr_t ignore, Duration const& timeout) const
308+
bool TimedPop(nullptr_t ignore, Duration const& timeout) const
287309
{
288-
int interval = 1;
289-
auto begin = std::chrono::high_resolution_clock::now();
290-
while (!TryPop(ignore)) {
291-
auto now = std::chrono::high_resolution_clock::now();
292-
if (std::chrono::duration_cast<Duration>(now - begin) >= timeout)
293-
return false;
294-
295-
interval = std::min(32, interval << 1);
296-
g_Scheduler.SleepSwitch(interval);
297-
}
298-
299-
return true;
310+
return impl_->TimedPop(ignore, timeout);
300311
}
301312

302313
bool Unique() const
@@ -329,6 +340,39 @@ class Channel<void>
329340
read_block_.CoBlockWait();
330341
}
331342

343+
// write
344+
template <typename Duration>
345+
bool TimedPush(nullptr_t ignore, Duration const& dur)
346+
{
347+
if (!write_block_.CoBlockWaitTimed(std::chrono::duration_cast<std::chrono::nanoseconds>(dur)))
348+
return false;
349+
350+
read_block_.Wakeup();
351+
return true;
352+
}
353+
354+
// read
355+
template <typename Duration>
356+
bool TimedPop(nullptr_t ignore, Duration const& dur)
357+
{
358+
write_block_.Wakeup();
359+
if (!read_block_.CoBlockWaitTimed(std::chrono::duration_cast<std::chrono::nanoseconds>(dur)))
360+
{
361+
if (write_block_.TryBlockWait())
362+
return false;
363+
else
364+
{
365+
while (!read_block_.TryBlockWait())
366+
if (write_block_.TryBlockWait())
367+
return false;
368+
else
369+
g_Scheduler.CoYield();
370+
}
371+
}
372+
373+
return true;
374+
}
375+
332376
// try write
333377
bool TryPush(nullptr_t ignore)
334378
{
@@ -352,8 +396,6 @@ class Channel<void>
352396
return true;
353397
}
354398
};
355-
356-
357399
};
358400

359401
} //namespace co

0 commit comments

Comments
 (0)