std::chrono::milliseconds(2000) 与 2000 毫秒
std::chrono::milliseconds(2000) vs 2000ms
我正在实现一个定时器库,
在 std::condition_variable::wait_until 的第二个参数中,std::chrono::steady_clock::now() + 2000ms
工作正常,
但 std::chrono::steady_clock::now() + std::chrono::milliseconds(2000)
不是。
请指导我缺少什么,以及以后如何使用。
/*
* Inspired by:
* https://www.fluentcpp.com/2018/12/28/timer-cpp/
* */
#include <thread>
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <iostream>
using namespace std;
class Timer {
std::condition_variable cv;
mutable std::mutex m;
bool is_killed = false;
bool is_reset = false;
std::thread active_thread;
void dispose_thread() {
if (active_thread.joinable()) {
kill();
active_thread.join();
}
is_killed = false; //safe, because all threads are dead
is_reset = false;
}
auto lock() const {
return std::unique_lock(m);
}
public:
[[maybe_unused]] void kill() {
auto l = lock();
is_killed = true;
is_reset = false;
cv.notify_all();
}
[[maybe_unused]] void reset() {
auto l = lock();
is_killed = false;
is_reset = true;
cv.notify_all();
}
~Timer() { dispose_thread(); }
template<class Function, class... Args, class Rep, class Period>
[[maybe_unused]] void once(const std::chrono::duration<Rep, Period> &sleep_duration, Function &&f, Args &&... args);
template<class Function, class... Args>
[[maybe_unused]] void fix_time_once(Function &&f, Args &&... args);
};
template<class Function, class... Args, class Rep, class Period>
void Timer::once(const std::chrono::duration<Rep, Period> &sleep_duration, Function &&f, Args &&... args) {
dispose_thread();
active_thread = std::thread(
[&, f = std::forward<Function>(f), args = std::make_tuple(std::forward<Args>(args)...)]() {
auto l = lock();
do {
is_reset = false;
cv.wait_until(l, std::chrono::steady_clock::now() + sleep_duration, [&] { return is_killed or is_reset; });
if (is_killed) return;
} while (is_reset);
std::apply(f, args);
});
}
template<class Function, class... Args>
void Timer::fix_time_once(Function &&f, Args &&... args) {
dispose_thread();
active_thread = std::thread(
[&, f = std::forward<Function>(f), args = std::make_tuple(std::forward<Args>(args)...)]() {
auto l = lock();
do {
is_reset = false;
cv.wait_until(l, std::chrono::steady_clock::now() + 2000ms, [&] { return is_killed or is_reset; });
if (is_killed) return;
} while (is_reset);
std::apply(f, args);
});
}
using namespace std;
#define LOGTIME std::time(nullptr)
void func2(const std::string_view str, const std::string_view str2) {
std::cout << LOGTIME << ": " << str << str2 << std::endl;
}
int main() {
Timer t = Timer();
Timer t2 = Timer();
std::cout << LOGTIME << ": " << "Program Starting" << std::endl;
t.once(std::chrono::milliseconds(2000), func2, "INCORRECT", " This should be std::chrono::milliseconds(2000) apart"); // not working as expected
t2.fix_time_once(func2, "CORRECT", " This is running as expected"); // working as expected
std::this_thread::sleep_for(std::chrono::seconds(10));
t.kill();
t2.kill();
return 1;
}
输出:
1611935262: Program Starting
1611935262: INCORRECT This should be std::chrono::milliseconds(2000) apart
1611935264: CORRECT This is running as expected
您正在将对临时 std::chrono::milliseconds(2000)
的引用传递到 Timer::once()
,然后传递到 lambda。
在完整表达式 (;
) 的末尾临时停止存在,因此当 lambda 在另一个线程中执行时 sleep_duration
成为悬空引用。
改为按值传递 sleep_duration
此处:
void Timer::once(std::chrono::duration<Rep, Period> sleep_duration, ...
这里:
[&, sleep_duration, f = std::forward<Function>(f), ...]() {
我正在实现一个定时器库,
在 std::condition_variable::wait_until 的第二个参数中,std::chrono::steady_clock::now() + 2000ms
工作正常,
但 std::chrono::steady_clock::now() + std::chrono::milliseconds(2000)
不是。
请指导我缺少什么,以及以后如何使用。
/*
* Inspired by:
* https://www.fluentcpp.com/2018/12/28/timer-cpp/
* */
#include <thread>
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <iostream>
using namespace std;
class Timer {
std::condition_variable cv;
mutable std::mutex m;
bool is_killed = false;
bool is_reset = false;
std::thread active_thread;
void dispose_thread() {
if (active_thread.joinable()) {
kill();
active_thread.join();
}
is_killed = false; //safe, because all threads are dead
is_reset = false;
}
auto lock() const {
return std::unique_lock(m);
}
public:
[[maybe_unused]] void kill() {
auto l = lock();
is_killed = true;
is_reset = false;
cv.notify_all();
}
[[maybe_unused]] void reset() {
auto l = lock();
is_killed = false;
is_reset = true;
cv.notify_all();
}
~Timer() { dispose_thread(); }
template<class Function, class... Args, class Rep, class Period>
[[maybe_unused]] void once(const std::chrono::duration<Rep, Period> &sleep_duration, Function &&f, Args &&... args);
template<class Function, class... Args>
[[maybe_unused]] void fix_time_once(Function &&f, Args &&... args);
};
template<class Function, class... Args, class Rep, class Period>
void Timer::once(const std::chrono::duration<Rep, Period> &sleep_duration, Function &&f, Args &&... args) {
dispose_thread();
active_thread = std::thread(
[&, f = std::forward<Function>(f), args = std::make_tuple(std::forward<Args>(args)...)]() {
auto l = lock();
do {
is_reset = false;
cv.wait_until(l, std::chrono::steady_clock::now() + sleep_duration, [&] { return is_killed or is_reset; });
if (is_killed) return;
} while (is_reset);
std::apply(f, args);
});
}
template<class Function, class... Args>
void Timer::fix_time_once(Function &&f, Args &&... args) {
dispose_thread();
active_thread = std::thread(
[&, f = std::forward<Function>(f), args = std::make_tuple(std::forward<Args>(args)...)]() {
auto l = lock();
do {
is_reset = false;
cv.wait_until(l, std::chrono::steady_clock::now() + 2000ms, [&] { return is_killed or is_reset; });
if (is_killed) return;
} while (is_reset);
std::apply(f, args);
});
}
using namespace std;
#define LOGTIME std::time(nullptr)
void func2(const std::string_view str, const std::string_view str2) {
std::cout << LOGTIME << ": " << str << str2 << std::endl;
}
int main() {
Timer t = Timer();
Timer t2 = Timer();
std::cout << LOGTIME << ": " << "Program Starting" << std::endl;
t.once(std::chrono::milliseconds(2000), func2, "INCORRECT", " This should be std::chrono::milliseconds(2000) apart"); // not working as expected
t2.fix_time_once(func2, "CORRECT", " This is running as expected"); // working as expected
std::this_thread::sleep_for(std::chrono::seconds(10));
t.kill();
t2.kill();
return 1;
}
输出:
1611935262: Program Starting
1611935262: INCORRECT This should be std::chrono::milliseconds(2000) apart
1611935264: CORRECT This is running as expected
您正在将对临时 std::chrono::milliseconds(2000)
的引用传递到 Timer::once()
,然后传递到 lambda。
在完整表达式 (;
) 的末尾临时停止存在,因此当 lambda 在另一个线程中执行时 sleep_duration
成为悬空引用。
改为按值传递 sleep_duration
此处:
void Timer::once(std::chrono::duration<Rep, Period> sleep_duration, ...
这里:
[&, sleep_duration, f = std::forward<Function>(f), ...]() {