2016-10-27 14 views
0

私は他の関数e.xを呼び出す関数TimeoutFunctionを書き込もうとしています。 printf、関数TimeoutFunctionがx秒以内に再度呼び出されなかった場合。再度呼び出された場合は、タイムアウトをリセットする必要があります。例えば このコード:FunctionAが5秒以内に再度呼び出されない場合はFunctionBを呼び出します

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は必要ではないが、私はそれを可視化するためにこれを追加しました。

+0

質問は私には明確ではありません。これは、古いテキスト端末の日に矢印キーを処理することを思い出させる。わかりませんが、解決しようとしている問題は何ですか? –

+0

TimeoutFunctionが一度呼び出されてから5秒後に呼び出されない場合は、他の関数e.xを呼び出す必要があります。 printf。 5秒以内にもう一度TimeoutFunctionが呼び出されると、タイムアウトは5秒にリセットされます –

+0

グローバル変数を使用して状態を追跡します – gj13

答えて

0

私は素敵ではないいくつかのコードを書いたが、私は誰かがよりよいコードを持っている場合、あなたは歓迎している

#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; 
} 

を除外としてそれが動作します。

+0

ええと、共有変数にアクセスするには相互排除が必要です。 –

0

私は、your self-answerに基づいて、これと同等の移植可能コードをコーディングしました。


しかし、最初:

あなたがあなた自身の答えに使用する技術はメインスレッド、またはワーカースレッドのいずれかが、任意の時点で共通の共有変数にアクセスしていることを保証する、スマートです。これは私の最初の考え方ではなく、明らかに私にはわかりませんでした。これらの変数への排他的アクセスを保証するために、mutexを使用するより簡単で効率的なコードになりました。

  • スレッドセーフにする必要があるrunningboolフラグ:しかし、あなたはそれをコード化されてきた方法で2つの同期問題があります。
    フラグがスレッドセーフでない場合、1つのスレッド(メインスレッドなど)で行われた変更は、いくつかのキャッシュに出力されますが、メインメモリへのすべての出力を行うわけではなく、同様に、キャッシュをチェックするだけで、メインメモリは直接チェックすることはできません。 3つの可能性は、std::atomic<bool>,std::atomic_flag(それほど都合がよいがロックフリーは保証されていない)であり、3つ目は余分なstd::mutexを使用する。 std::unique_lockと組み合わされている。

  • TimeoutFunction関数では、のスレッドの後に共有状態の更新をにする必要があります。
    完全性のために、GetTickCount結果は、スレッドに参加するのを待つ前にローカル変数に格納する必要があります。

    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"); 
    } 
    
    main関数はこの(ほぼ正確にあなたの投稿の答えのように同じことをやって)に似ている標準C++うまくいけば、ポータブルコードの場合


再利用をサポートする2つの主要な抽象は、

    です。
  • スレッドの通信状態をグローバルではなくオブジェクトに置きます。

  • ハードコードされたアクションではなく、アクションをパラメータ化します。

    cppxクラス-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の実装には、いくつかの一般的なサポートのものを使用しています標準ライブラリのもののラップと名前の変更、標準ライブラリベースのあなたのアイデアの再実装、t彼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 
関連する問題