如何设置一个 "precise" 周期性定时器来监控 Linux(C/C++) 中的内容?

How to setup a "precise" periodic timer to monitor stuff in Linux(C/C++)?

我正在玩弄监控的东西。为此,我喜欢定期监控引脚等。监控应用程序应该 运行 在用户 space 中并用 C/C++ 编写。我正在寻找一个很好的实践来解决这个领域的问题。

已经有一个关于使用定时器的很好的答案 here。我的问题更笼统。计时器是最好的解决方案还是等待信号量超时?等等

我把一些伪代码作为讨论的基础:

// sample with 1kHz
#define fs 1000
// sample time
#define Ts 1.0/fs

// sample data structure
typedef struct sampleStruct {
   struct timespec ts;
   int sampleData[10];
} sampleType;

void monitorCallback(sampleType * pS) {

}

void sampleThread() {
  sampleType s;
  struct timespec workingtime;
  for (;;) {
     // get a timestamp
     timespec_get(&(s.ts), TIME_UTC);
     // sample data
     monitorCallback(s);
     // try to measure the time we spent for obtaining the sample
     timespec_get(&workingtime, TIME_UTC);
     // try to minimize the jitter by correcting the sleeping time
     sleep(Ts - (workingtime - s.ts));
  }
}

我正在寻找解决方案,定期对信号等进行采样,喜欢detect/measure两个样本之间的抖动并使用函数获取样本信号数据。

欢迎提出任何想法!

您必须假设 sleep() 和 "measuring of the monitoring time" 都非常不精确。

如果您想定期监控事情,您必须更改代码以等到下一个有趣的时间点,例如:

void sampleThread() {
    sampleType s;

    for (;;) {
        // get a timestamp
        timespec_get(&(s.ts), TIME_UTC);
        // sample data
        monitorCallback(s);
        // Wait until the next sampling time.
        struct timespec now;
        timespec_get(&now, TIME_UTC);  
        sleep(now - s.ts);
    }
}

最重要的一点是 sleep/wait 直到下一个绝对时间点,并仅根据您的目标间隔计算下一个绝对时间点,而不是根据任何测量时间或任何东西。这样 sleep() 和执行时间中的任何不准确都无关紧要。在上面的代码中,您可以用 sleep((now - s.ts) / 2) 替换 sleep() 调用,它仍然会在长 运行 中达到目标频率(就像一个只睡觉的睡眠实现的极端例子要求的一半)。

我不会强加你应该如何使用线程,因为这取决于你的其他代码。
从 C++11 开始有一个时间操作模块 (std::chrono) in the standard library. Use it with std::this_thread::sleep_until:

#include <chrono>
#include <thread>

// ... in your code ...
namespace chr = std::chrono;
// steady_clock is better than system_clock in this case.
// You should also consider high_resolution_clock.
auto currentTime = chr::steady_clock::now();
auto targetTime = currentTime + chr::seconds{30};
// sleep until the targetTime
std::this_thread::sleep_until(targetTime);

没有。这对您的目的不起作用。 Linux 不是 RTOS,绝对不能保证您的进程会在请求的时间被唤醒。它甚至不是 C++ 问题,而是 OS 问题。

据我所知,实现你在 Linux 上所做的事情的最佳方法是将 real-time 进程绑定到隔离的 CPU,忙等待并等待某个特定的进程在下一个样本之前要经过的 CPU 个循环数。

使用函数:setitimer() 这里是一个简单的例子:

struct itimerval tv;
tv.it_interval.tv_sec = 0;
tv.it_interval.tv_usec = 100000;  // when timer expires, reset to 100ms
tv.it_value.tv_sec = 0;
tv.it_value.tv_usec = 100000;   // 100 ms == 100000 us
setitimer(ITIMER_REAL, &tv, NULL);

并使用 struct sigaction.

定期捕获计时器

下面是一个简单的使用示例:struct sigaction:

struct sigaction psa;
psa.sa_handler = pSigHandler;   // << use the name of your signal hander
sigaction(SIGTSTP, &psa, NULL);

下面是函数的简单实现:pSigHandler()

static void pSigHandler(int signo)
{
    switch (signo) 
    {
            case SIGTSTP:
                printf("TSTP");
                fflush(stdout);
                break;
    }
}

当然,要使以上所有工作正常,需要以下两个语句:

#include <stdio.h>
#include <signal.h>

上面的代码有问题,有一长串函数'should'不能在信号处理程序中使用。 printf() 是有问题的函数之一。我的建议是让信号处理函数设置一个标志,然后让主函数监视该标志,并在找到时 'set'、重置它并执行必要的活动。