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: /**

我真正喜欢做的是以下几点

  • 有人可以多次调用foo(data)并将它们存储在数据库中
  • 每当调用foo(data)时,它都会启动一个计时器几秒钟
  • 当计时器倒计时时,foo(数据)可以被称为多个 可以存储时间和多个项目,但在计时器完成之前不调用擦除
  • 每当定时器启动时, “remove”函数被调用一次,以从数据库中删除所有记录 db
  • 基本上,我希望能够完成一项任务,并等待几秒钟,然后在几秒钟后批量完成一项单批任务B

    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" );
    }