如果函数 A 在 5 秒内未再次调用,则调用函数 B

  • 本文关键字:调用 函数 如果 c++ timeout
  • 更新时间 :
  • 英文 :


我试图写一个函数TimeoutFunction,它调用另一个函数例如printf,如果函数TimeoutFunction在x秒内没有再次调用。如果再次调用它,则应该重置超时。下面的代码例如:

void TimeoutFunction(string MyString)
{
    //Wait 5 seconds and then call printf(MyString)
}
int main()
{
    TimeoutFunction("A");
    Sleep(4);
    TimeoutFunction("B");
    Sleep(6);
    TimeoutFunction("C");
    Sleep(10);
    TimeoutFunction("D");
    Sleep(2);
    TimeoutFunction("E");
}

打印:BCE或至少BC

参数MyString不是必需的,但我添加它是为了使其可视化。

我写了一些不太好的代码,但它可以正常工作

#include <thread>
#include <windows.h>
bool running;
unsigned long StartTime;
unsigned int WaitTime = 500;
const char* PrintString;
std::thread InternThread;
void MyPrint()
{
    while (running)
    {
        auto WaitedTime = GetTickCount() - StartTime;
        if (WaitedTime > WaitTime)
        {
            printf(PrintString);
            break;
        }
        Sleep(10);
    }
}

void TimeoutFunction(const char* MyString)
{
    StartTime = GetTickCount();
    PrintString = MyString;
    running = false;
    if (InternThread.joinable())
    {
        InternThread.join();
    }
    running = true;
    InternThread = std::thread(MyPrint);
}
int main()
{
    TimeoutFunction("A");
    Sleep(400);
    TimeoutFunction("B");
    Sleep(600);
    TimeoutFunction("C");
    Sleep(1000);
    TimeoutFunction("D");
    Sleep(200);
    TimeoutFunction("E");
    InternThread.join();
    return 0;
}

如果有人有更好的代码,欢迎你。

我已经根据你的自我回答编写了等价的希望可移植的代码。


但首先:

您在自己的答案中使用的技术是聪明的,确保主线程或工作线程在任何时候都在访问公共共享变量。这不是我对如何做到这一点的第一个想法,也就是说,它对我来说并不明显,它使代码比使用互斥锁来确保对这些变量的独占访问更简单,更有效。但是,您编写它的方式存在两个同步问题:

  • bool标志running需要设置为线程安全。
    如果该标志不是线程安全的,那么在一个线程(例如主线程)中所做的更改可能只是将其发送到一些缓存,而不是所有的方式发送到主存,同样,另一个线程的检查可能只是检查缓存,而不是直接检查主存。三种可能是std::atomic<bool>, std::atomic_flag(不太方便但保证无锁),第三种可能是使用额外的std::mutex,例如与std::unique_lock结合使用。

  • TimeoutFunction函数中,共享状态更新需要在加入线程后进行
    在等待线程加入之前,GetTickCount结果应该存储在一个局部变量中。


对于标准c++希望可移植的代码,main函数是这样的(与您发布的答案几乎完全相同):

<我> main.cpp:
#include <stdio.h>                  // printf
#include <Delayed_action.hpp>       // my::(Delayed_action, sleep)
// Alternative to defining lots of small lambdas, a special case functor:
struct Print
{
    char const* s; 
    void operator()() const { printf( "%s", s ); }
    Print( char const* const a_literal ): s( a_literal ) {}
};
auto main()
    -> int
{
    using my::Delayed_action; using my::sleep;
    using namespace std::literals;  // ms
    Delayed_action da;
    da.set_action( Print{ "A" } );
    sleep( 400ms );
    da.set_action( Print{ "B" } );
    sleep( 600ms );
    da.set_action( Print{ "C" } );
    sleep( 1000ms );
    da.set_action( Print{ "D" } );
    sleep( 200ms );
    da.set_action( Print{ "E" } );
    da.wait_for_action_completed();
    printf( "n" );
}

这里支持重用的两个主要抽象是

  • 将线程通信状态置于对象中,而不是全局变量。

  • 参数化动作,而不是硬编码的动作

Delayed_action的实现使用了一些通用的支持材料:

<我> cppx-class-kinds.hpp:
#pragma once
namespace cppx {
    class No_copy
    {
    private:
        auto operator=( No_copy const& ) -> No_copy& = delete;
        No_copy( No_copy const& ) = delete;
    public:
        auto operator=( No_copy&& ) -> No_copy& { return *this; }
        No_copy() {}
        No_copy( No_copy&& ) {}
    };
    class No_move
    {
    private:
        auto operator=( No_move&& ) -> No_move& = delete;
        No_move( No_move&& ) = delete;
    public:
        auto operator=( No_move const& ) -> No_move& { return *this; }
        No_move() {}
        No_move( No_move const& ) {}
    };
    class No_copy_or_move
        : public No_copy
        , public No_move
    {};
}  // namespace cppx
<我> cppx-threading.hpp:
#pragma once
#include <cppx-class-kinds.hpp>     // cppx::No_copy_or_move
#include <atomic>           // std::atomic
#include <chrono>           // std::chrono::milliseconds
#include <thread>           // std::thread
namespace cppx {
    namespace this_thread = std::this_thread;
    inline namespace std_aliases {
        using Milliseconds      = std::chrono::milliseconds;
        using Steady_clock      = std::chrono::steady_clock;
        using Time_point        = std::chrono::time_point<Steady_clock>;
        using Thread            = std::thread;    
    }
    inline void sleep( Milliseconds const duration )
    {
        this_thread::sleep_for( duration );
    }
    // Syntactic sugar for std::atomic_flag:
    // • boolean assignment
    // • default init to false.
    // std::atomic_flag is guaranteed lock free, as opposed to std::atomic<bool>.
    // Cost: there's no way to check the value except by setting it to true.
    class Atomic_flag
        : public No_copy_or_move
    {
    private:
        std::atomic_flag    flag_   = ATOMIC_FLAG_INIT; // Initialized to false.
    public:
        void clear() { flag_.clear(); }
        auto test_and_set() -> bool
        {
            bool const previous_value = flag_.test_and_set();
            return previous_value;
        }
        void set() { test_and_set(); }
        void operator=( bool const should_be_set )
        {
            if( should_be_set ) set(); else clear();
        }
        Atomic_flag() {}
    };
}  // namespace cppx

通过包装和重命名标准库的东西,基于标准库的重新实现您的想法,Delayed_action类,可以看起来像这样:

<我> Delayed_action.hpp:
#pragma once
#include <cppx-class-kinds.hpp> // cppx::No_copy_or_move
#include <cppx-threading.hpp>   // cppx::(Atomic_flag, sleep)
#include <functional>           // std::(function, ref)
#include <utility>              // std::move
namespace my {
    using namespace cppx::std_aliases;
    using namespace std::literals;
    using cppx::Atomic_flag;
    using cppx::No_copy_or_move;
    using cppx::sleep;
    using std::move;
    using std::ref;
    using Action = std::function<void()>;
    class Delayed_action
        : public No_copy_or_move
    {
    private:
        struct Parameters
        {
            Atomic_flag     run;
            Action          action;
            Time_point      when;
        };
        static void polling( Parameters& parameters )
        {
            for( ;; )
            {
                if( not parameters.run.test_and_set() )
                {
                    return;
                }
                else if( Steady_clock::now() >= parameters.when )
                {
                    parameters.action();
                    return;
                }
                sleep( 10ms );
            }
        }
    private:
        Parameters  parameters_;
        Thread      worker_;
        void join_worker_thread()
        {
            if( worker_.joinable() )
            {
                worker_.join();
            }
        }
        void end_worker_thread()
        {
            parameters_.run = false;
            join_worker_thread();
        }
    public:
        static auto default_delay() -> Milliseconds { return 500ms; }
        void set_action( Action action, Milliseconds const delay = default_delay() )
        {
            Time_point const when = Steady_clock::now() + delay;
            end_worker_thread();
            parameters_.action = move( action );
            parameters_.when = when;
            parameters_.run = true;
            worker_ = Thread( &polling, ref( parameters_ ) );
        }
        void wait_for_action_completed() { join_worker_thread(); }
        ~Delayed_action() { end_worker_thread(); }
        Delayed_action() {}
        Delayed_action( Action action, Milliseconds const delay = default_delay() )
        {
            set_action( move( action ), delay );
        }
    };
}  // namespace my

相关内容

  • 没有找到相关文章

最新更新