C++;回调定时器实现 我发现了在C++应用程序中使用的回调定时器的以下实现。然而,这个实现要求我从start调用方“加入”线程,这有效地阻止了start函数的调用方
我真正喜欢做的是以下几点C++;回调定时器实现 我发现了在C++应用程序中使用的回调定时器的以下实现。然而,这个实现要求我从start调用方“加入”线程,这有效地阻止了start函数的调用方,c++,multithreading,timer,pthreads,C++,Multithreading,Timer,Pthreads,我真正喜欢做的是以下几点 有人可以多次调用foo(data)并将它们存储在数据库中 每当调用foo(data)时,它都会启动一个计时器几秒钟 当计时器倒计时时,foo(数据)可以被称为多个 可以存储时间和多个项目,但在计时器完成之前不调用擦除 每当定时器启动时, “remove”函数被调用一次,以从数据库中删除所有记录 db 基本上,我希望能够完成一项任务,并等待几秒钟,然后在几秒钟后批量完成一项单批任务B class CallBackTimer { public: /**
class CallBackTimer {
public:
/**
* Constructor of the CallBackTimer
*/
CallBackTimer() :_execute(false) { }
/**
* Destructor
*/
~CallBackTimer() {
if (_execute.load(std::memory_order_acquire)) {
stop();
};
}
/**
* Stops the timer
*/
void stop() {
_execute.store(false, std::memory_order_release);
if (_thd.joinable()) {
_thd.join();
}
}
/**
* Start the timer function
* @param interval Repeating duration in milliseconds, 0 indicates the @func will run only once
* @param delay Time in milliseconds to wait before the first callback
* @param func Callback function
*/
void start(int interval, int delay, std::function<void(void)> func) {
if(_execute.load(std::memory_order_acquire)) {
stop();
};
_execute.store(true, std::memory_order_release);
_thd = std::thread([this, interval, delay, func]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if (interval == 0) {
func();
stop();
} else {
while (_execute.load(std::memory_order_acquire)) {
func();
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
}
}
});
}
/**
* Check if the timer is currently running
* @return bool, true if timer is running, false otherwise.
*/
bool is_running() const noexcept {
return ( _execute.load(std::memory_order_acquire) && _thd.joinable() );
}
private:
std::atomic<bool> _execute;
std::thread _thd;
};
类回调计时器{
公众:
/**
*回调计时器的构造函数
*/
CallBackTimer():_execute(false){}
/**
*析构函数
*/
~CallBackTimer(){
if(_execute.load(std::memory_order_acquire)){
停止();
};
}
/**
*停止计时器
*/
无效停止(){
_execute.store(false,std::memory\u order\u release);
如果(_thd.joinable()){
_thd.join();
}
}
/**
*启动定时器功能
*@param interval重复持续时间(毫秒),0表示@func仅运行一次
*@param在第一次回调之前等待的延迟时间(毫秒)
*@param func回调函数
*/
无效开始(整数间隔、整数延迟、标准::函数func){
if(_execute.load(std::memory_order_acquire)){
停止();
};
_execute.store(true,std::memory\u order\u release);
_thd=std::thread([this,interval,delay,func](){
std::this_线程::sleep_for(std::chrono::毫秒(延迟));
如果(间隔==0){
func();
停止();
}否则{
while(_execute.load(std::memory_order_acquire)){
func();
std::this_线程::sleep_for(std::chrono::毫秒(间隔));
}
}
});
}
/**
*检查计时器当前是否正在运行
*@return bool,如果计时器正在运行,则为true,否则为false。
*/
bool正在运行()const noexcept{
返回(_execute.load(std::memory_order_acquire)&&&&u thd.joinable());
}
私人:
std::原子执行;
标准:螺纹螺纹;
};
我已尝试使用thread.detach()修改上述代码。但是,我在分离的线程中运行问题,无法从数据库写入(擦除)
感谢您的帮助和建议 您可以使用
std::async
而不是使用线程。下面的类将在添加最后一个字符串后4秒的顺序处理排队的字符串。一次只启动一个异步任务,并且std::aysnc
为您处理所有线程
如果类被销毁时队列中有未处理的项,那么异步任务将停止而不等待,并且这些项不会被处理(但如果这不是您想要的行为,则很容易更改)
#包括
#包括
#包括
#包括
#包括
#包括
类批处理程序
{
公众:
批处理程序()
:任务延迟(4),
startTime(std::chrono::staddy_clock::now())//仅用于调试
{
}
无效队列(常量std::字符串和值)
{
std::unique_locklock(互斥锁);
std::cout lock(互斥锁);
//循环直到std::chrono::Standy_clock::now()>超时
自动等待=超时-std::chrono::staid_clock::now();
当(!关闭并等待>标准::计时::秒(0))
{
条件。等待(锁定,等待);
wait=timeout-std::chrono::staid_clock::now();
}
如果(!关闭)
{
std::您能添加一个示例来说明如何使用这个类吗?您所要求的似乎是危险的和不必要的。也许您可以在构造函数中构造线程并将其加入到析构函数中?然后您只需要一个std::队列就可以通过start()向中添加新项(回调)并通过stop()刷新所有元素。一旦它超出范围,析构函数将处理线程。然后线程中会有一个while循环,在队列中有任何项目之前产生。然后开始处理它。下一个while循环将检查计时器和项目数。在内部,它将处理项目1乘1。然后让它重复,直到停止。析构函数将进行清理。我猜是interval正在项目之间等待,延迟只是它的触发时间。感谢您的回答,实际上我发现根本问题不是因为CallbackTimer/Batcher。出于某种原因,回调中的sqlite语句(在您的例子中,auto function=work.front()&&function()中)
将执行从表中删除行的操作,但不会实际删除行。
#include <iostream>
#include <string>
#include <future>
#include <mutex>
#include <chrono>
#include <queue>
class Batcher
{
public:
Batcher()
: taskDelay( 4 ),
startTime( std::chrono::steady_clock::now() ) // only used for debugging
{
}
void queue( const std::string& value )
{
std::unique_lock< std::mutex > lock( mutex );
std::cout << "queuing '" << value << " at " << std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::steady_clock::now() - startTime ).count() << "ms\n";
work.push( value );
// increase the time to process the queue to "now + 4 seconds"
timeout = std::chrono::steady_clock::now() + taskDelay;
if ( !running )
{
// launch a new asynchronous task which will process the queue
task = std::async( std::launch::async, [this]{ processWork(); } );
running = true;
}
}
~Batcher()
{
std::unique_lock< std::mutex > lock( mutex );
// stop processing the queue
closing = true;
bool wasRunning = running;
condition.notify_all();
lock.unlock();
if ( wasRunning )
{
// wait for the async task to complete
task.wait();
}
}
private:
std::mutex mutex;
std::condition_variable condition;
std::chrono::seconds taskDelay;
std::chrono::steady_clock::time_point timeout;
std::queue< std::string > work;
std::future< void > task;
bool closing = false;
bool running = false;
std::chrono::steady_clock::time_point startTime;
void processWork()
{
std::unique_lock< std::mutex > lock( mutex );
// loop until std::chrono::steady_clock::now() > timeout
auto wait = timeout - std::chrono::steady_clock::now();
while ( !closing && wait > std::chrono::seconds( 0 ) )
{
condition.wait_for( lock, wait );
wait = timeout - std::chrono::steady_clock::now();
}
if ( !closing )
{
std::cout << "processing queue at " << std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::steady_clock::now() - startTime ).count() << "ms\n";
while ( !work.empty() )
{
std::cout << work.front() << "\n";
work.pop();
}
std::cout << std::flush;
}
else
{
std::cout << "aborting queue processing at " << std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::steady_clock::now() - startTime ).count() << "ms with " << work.size() << " remaining items\n";
}
running = false;
}
};
int main()
{
Batcher batcher;
batcher.queue( "test 1" );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
batcher.queue( "test 2" );
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
batcher.queue( "test 3" );
std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
batcher.queue( "test 4" );
std::this_thread::sleep_for( std::chrono::seconds( 5 ) );
batcher.queue( "test 5" );
}