比較的低い解像度でコールバックを実行するタイマーが必要です。そのような C++ タイマー クラスを Linux で実装する最良の方法は何ですか? 使用できるライブラリはありますか?
5 に答える
フレームワーク (Glib、Qt、Wx など) 内で記述している場合は、タイミング コールバック機能を備えたイベント ループが既に存在します。そうではないと仮定します。
独自のイベント ループを記述している場合は、独自のイベント ディスパッチャにgettimeofday
/select
ペア ( struct timeval
、マイクロ秒精度) またはclock_gettime
/nanosleep
ペア ( struct timespec
、ナノ秒精度) を使用できます。後者のインターフェースの方が解像度は高いですが、とにかくスケジューリングがそれほど正確ではないため、最適なものを選択してください。
#include <algorithm>
#include <functional>
#include <vector>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
using namespace std;
class scheduler {
public:
scheduler();
int events();
void addEvent(const struct timeval, int (*)(void *), void *);
int dispatchUntil(const struct timeval &);
bool waitUntil(const struct timeval * = NULL);
int loopUntil(const struct timeval * = NULL);
private:
static bool tv_le(const struct timeval &, const struct timeval &);
struct event {
struct timeval when;
int (*callback)(void *);
void *data;
};
static struct _cmp
: public binary_function<bool, const struct event &, const struct event &>
{
bool operator()(const struct event &a, const struct event &b) {
return !tv_le(a.when, b.when);
}
} cmp;
vector<struct event> heap;
};
bool scheduler::tv_le(const struct timeval &a, const struct timeval &b) {
return a.tv_sec < b.tv_sec ||
a.tv_sec == b.tv_sec && a.tv_usec <= b.tv_usec;
}
scheduler::scheduler() : heap() {}
int scheduler::events() {
return heap.size();
}
void scheduler::addEvent(const struct timeval when, int (*callback)(void *), void *data) {
struct event ev = {when, callback, data};
heap.push_back(ev);
push_heap(heap.begin(), heap.end(), cmp);
}
int scheduler::dispatchUntil(const struct timeval &tv) {
int count = 0;
while (heap.size() > 0 && tv_le(heap.front().when, tv)) {
struct event ev = heap.front();
pop_heap(heap.begin(), heap.end(), cmp);
heap.pop_back();
ev.callback(ev.data);
count++;
}
return count;
}
bool scheduler::waitUntil(const struct timeval *tv) {
if (heap.size() > 0 && (!tv || tv_le(heap.front().when, *tv)))
tv = &heap.front().when;
if (!tv)
return false;
struct timeval tv2;
do {
gettimeofday(&tv2, NULL);
if (tv_le(*tv, tv2))
break;
tv2.tv_sec -= tv->tv_sec;
if ((tv2.tv_usec -= tv->tv_usec) < 0) {
tv2.tv_sec--;
tv2.tv_usec += 1000000;
}
} while (select(0, NULL, NULL, NULL, &tv2) < 0 && errno == EINTR);
return heap.size() > 0 && tv_le(*tv, heap.front().when);
}
int scheduler::loopUntil(const struct timeval *tv) {
int counter = 0;
while (waitUntil(tv))
counter += dispatchUntil(heap.front().when);
return counter;
}
警告: 私は C が大好きです。C++ を書いたことはありません。私はその言語を知っているふりをしているだけです。
免責事項: 作成したばかりで、まったくテストされていません。基本的な考え方は、イベントを優先キューに保持し、最初のイベントまで待って実行し、繰り返すことです。
boost::asio ライブラリを使用します。コールバックを呼び出す同期タイマーと非同期タイマーの両方があります。
http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio/tutorial.html
ここにタイマークラスのリンクがあります。タイマーを作成し、自動リロードするかどうかの値を渡すだけです。コールバック関数へのポインタ。そして、それをスレッドまたはシグナルで処理したい場合。シグナルを選択した場合は、シグナルも渡す必要があります。
http://timerlinux.codeplex.com/
タイマーやシグナルについてもっと勉強したい場合は、Linux システム プログラミングという良い本があります。あなたは3つの章とそれをすべて説明するだけを読む必要があります.
time.h ヘッダーの timeval 構造体が探しているものです。秒単位とナノ秒単位の時間があります。ナノ秒単位の合計時間は、timeval.tv_sec * 1000000 + timeval.tv_usec です。簡単だと思います。
#include <time.h>
timeval theStartTime;
gettimeofday(&theStartTime);
std::cout<<"The time we got's seconds field = "<<theStartTime.tv_sec<<std::endl;
std::cout<<"The time we got's nanoseconds field = "<<theStartTime.tv_usec<<std::endl;