19

関数を呼び出して別の関数をXミリ秒で呼び出すように要求できるように、C++でシステムを実装したいと思います。このようなもの:

callfunctiontimed(25, funcName);

25は、関数が呼び出されるまでのミリ秒数です。

これにマルチスレッドが必要かどうかを知り、遅延機能を使用しますか?関数ポインタを使用する以外に、このような機能はどのように機能しますか?

4

4 に答える 4

18

ポータブルソリューションの場合、boost::asioを使用できます。以下は私が少し前に書いたデモです。あなたになら変えられる

t.expires_from_now(boost::posix_time::seconds(1));

それに合わせて、200ミリ秒後に関数呼び出しを行う必要があります。

t.expires_from_now(boost::posix_time::milliseconds(200)); 

以下は完全な実例です。何度も電話をかけていますが、少し変更するだけで一度だけ電話がかけやすいと思います。

#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using namespace boost::asio;
using namespace std;

class Deadline 
{
public:
    Deadline(deadline_timer &timer) : t(timer) {
        wait();
    }

    void timeout(const boost::system::error_code &e) {
        if (e)
            return;
        cout << "tick" << endl;
        wait();
    }

    void cancel() {
        t.cancel();
    }


private:
    void wait() {
        t.expires_from_now(boost::posix_time::seconds(1)); //repeat rate here
        t.async_wait(boost::bind(&Deadline::timeout, this, boost::asio::placeholders::error));
    }

    deadline_timer &t;
};


class CancelDeadline {
public:
    CancelDeadline(Deadline &d) :dl(d) { }
    void operator()() {
        string cancel;
        cin >> cancel;
        dl.cancel();
        return;
    }
private:
    Deadline &dl;
};



int main()
{
    io_service io;
    deadline_timer t(io);
    Deadline d(t);
    CancelDeadline cd(d);
    boost::thread thr1(cd);
    io.run();
    return 0;
}



//result:
//it keeps printing tick every second until you enter cancel and enter in the console
tick
tick
tick
于 2012-10-15T23:22:13.053 に答える
7

メインの実行スレッドをブロックせずに25ミリ秒が終了したときにコールバックが実行されるように、非同期で実行しますか?その場合、実装するタイマー/時限コールバック関数とは別のスレッドでコールバックを実行できます。

マルチスレッドを使用しない場合は、メイン関数またはcallfunctiontimed(25、funcName);の呼び出し関数。あなたがsleep/usleepを実行している間ブロックします。実装する動作については、今すぐ選択できます。

実際の解決策は、マルチスレッドであるかどうかほど単純ではありません。関数が異なるタイムアウトと関数で複数回呼び出される可能性があることを考慮して、どのように異なるタイマー/コールバック情報を保持するかなどがあります。

それを行う1つの方法は、次のようになります。

  1. タイマー/コールバックのソート済みリストを作成し、有効期限に基づいてソートします。
  2. メインスレッドとコールバック/タイマーを調べる1つのスレッドがあり、それをタイマースレッドと呼びます。
  3. 新しいコールバックが追加されたら、ソート済みリストに追加します。
  4. タイマースレッドは、ソートされたリストまたはヘッドで最小の時間待機するように初期化できます。新しいコールバックが追加されたら、再初期化します。世話をするいくつかの数学と条件があるでしょう。
  5. タイマースレッドがスリープ状態になると、リストの先頭を削除して調べ、新しいスレッドで関数ポインターを実行します。タイマースレッドは、リストの新しい先頭のスリープ時間で再初期化されます。

    main() {
            //spawn a timer thread with pthread create 
    
        callfunctiontimed(25, test); 
        callfunctiontimed(35, show);
        callfunctiontimed(4,  print);
    }
    
    callfunctionTImed(int time, (func*)function, void*data) //
    {
        //add information to sorted list of timer and callbacks
        //re-initialize sleep_time for timer thread if needed. 
        return. 
    }
    timerThread() {
        while(1){
         sleep(sleep_time);
         //look at head of timer list, remove it, call function in a new thread   
         //adjust sleep time as per new head     
        }
    }
    

これは完璧ではなく、いくつかの問題がありますが、うまくいけば、これは私が何を意味したのかを理解するのに役立ちます。

于 2012-10-15T21:27:45.687 に答える
6

多くの人がこの問題について良い答えを提供してくれましたが、私は数年前に同様の問題を抱えていたので、直接質問に答えます。いくつかの理由でBoostを使用できませんでした。Boostは多くのオープンソースソフトウェアで優れた用途を持っていることを私は知っています。さらに、 Linuxベースの環境に関連するタイマーとコールバックを具体的に理解したかったのです。だから、私は自分で書いた。

基本的に、私にはTimerクラスとTimerCallbackクラスがあります。クラスの継承クラスとして実装される一般的なコールバックは、TimerCallbackコールバック時に実行される操作をtriggered ()メソッドに配置し、ニーズに合わせて特別に実装されます。

通常のセマンティクスでは、Timerオブジェクトはコールバックオブジェクトに関連付けられています。このオブジェクトには、コールバックの実行に必要なすべての情報が含まれていると考えられます。タイマーのスケジューリングは、別のスレッド/プロセスで維持する必要がある1つの環境全体のタイマーminheapによって管理されます。このminheapタスクは、1つのことだけを実行します。それは、将来設定されるコールバックイベントのminheapをminheapします。minheapは、起動する次のイベントを選択し、タイマーイベントO(1)の残りのイベントをminheap化できます。また、に新しいタイマーイベントを挿入することもできます(ヒープの簡単な紹介をここで読んでください)。O(log n)nO(log n)

タイマーが起動すると、minheapスケジューラーは、それが定期タイマー、ワンショットタイマー、または特定の回数実行されるタイマーであるかどうかを確認します。したがって、タイマーオブジェクトは、minheapから削除されるか、次の実行時間でminheapに再挿入されます。タイマーオブジェクトを削除する場合は、最小ヒープから削除され(ただし、タイマーオブジェクトの削除は、それを作成したタスクに任せられる場合とされない場合があります)、残りのヒープは最小ヒープ化されます。つまり、minheapプロパティを満たすように再配置されます。

動作し、単体テストされた実装がここにあり、バグが含まれている可能性があります(私のアプリケーションから抜粋)が、誰かに役立つかもしれないと思いました。実装はマルチプロセス(fork()ed-process)ベースであり(pthreadメインタスク(process)でもsを使用します)、プロセス間の通信にPOSIX共有メモリとPOSIXメッセージキューを使用します。

于 2013-03-23T23:37:52.413 に答える
3

Windowsでは、次のようになります-http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v SetTimer= vs.85 ).aspx

サンプルコード:

#define STRICT 1 
#include <windows.h>
#include <iostream.h>

VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{




  cout << "CALLBACK " << dwTime << '\n';
  cout.flush();
}

int main(int argc, char *argv[], char *envp[]) 
{
    int Counter=0;
    MSG Msg;

    UINT TimerId = SetTimer(NULL, 0, 2000, &TimerProc); //2000 milliseconds

    cout << "TimerId: " << TimerId << '\n';
   if (!TimerId)
    return 16;

   while (GetMessage(&Msg, NULL, 0, 0)) 
   {
        ++Counter;
        if (Msg.message == WM_TIMER)
        cout << "Counter: " << Counter << "; timer message\n";
        else
        cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
        DispatchMessage(&Msg);
    }

   KillTimer(NULL, TimerId);
return 0;
}
于 2012-10-15T21:29:55.790 に答える