Tencent/flare

Timer

4kangjc opened this issue · 6 comments

std::uint64_t SetTimer(std::chrono::steady_clock::time_point at,
std::chrono::nanoseconds interval,
Function<void(std::uint64_t)>&& cb) {
// This is ugly. But since we have to start a fiber each time user's `cb` is
// called, we must share it.
//
// We also take measures not to call user's callback before the previous call
// has returned. Otherwise we'll likely crash user's (presumably poor) code.
struct UserCallback {
void Run(std::uint64_t tid) {
if (!running.exchange(true, std::memory_order_acq_rel)) {
cb(tid);
}
running.store(false, std::memory_order_relaxed);
// Otherwise this call is lost. This can happen if user's code runs too
// slowly. For the moment we left the behavior as unspecified.
}
Function<void(std::uint64_t)> cb;
std::atomic<bool> running{};
};
auto ucb = std::make_shared<UserCallback>();
ucb->cb = std::move(cb);
auto sg = detail::NearestSchedulingGroup();
auto timer_id = sg->CreateTimer(at, interval, [ucb](auto tid) mutable {
internal::StartFiberDetached([ucb, tid] { ucb->cb(tid); });
});
sg->EnableTimer(timer_id);
return timer_id;
}

没有看懂UserCallback的作用, Run函数完全没有调用啊, running也就显得乏力了

确实写错了,感谢反馈,我处理下。

本意是避免多个fiber同时调用用户的callback,不然容易导致线程安全问题。因为一般除非极端情况下timer运行的特别慢,不然不会导致多个timer同时跑,所以对用户来说大多数情况下在timer里面加锁也没太大意义。

UserCallback的另外一个目的是为了在下面套上shared_ptr,提供CopyConstructible,不然没法多次StartFiberDetached。(不过单纯就这一点来说其实shared_ptr<function>也是一样的)

确实写错了,感谢反馈,我处理下。

本意是避免多个fiber同时调用用户的callback,不然容易导致线程安全问题。因为一般除非极端情况下timer运行的特别慢,不然不会导致多个timer同时跑,所以对用户来说大多数情况下在timer里面加锁也没太大意义。

UserCallback的另外一个目的是为了在下面套上shared_ptr,提供CopyConstructible,不然没法多次StartFiberDetached。(不过单纯就这一点来说其实shared_ptr<function>也是一样的)

是不是要把if换成while, 多个fiber同时调用用户的callback, 就只执行其中的一个吗?

本来的想法是采取一个跟Windows类似的做法,避免因为timer处理不过来导致一直在跑个不停

不过现在想想这个做法可能确实容易给用户一些非预期的结果,而且很难定位到问题出在这里,可能确实while (remining--)更合适些

timer可以把文档补全一下,或者我来也行,我想想怎么写

timer可以把文档补全一下,或者我来也行,我想想怎么写

有时间再写, 不定时:)

README中的[调度组](flare/), 这里文档没有链接上