如何设置一个 "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'、重置它并执行必要的活动。
我正在玩弄监控的东西。为此,我喜欢定期监控引脚等。监控应用程序应该 运行 在用户 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'、重置它并执行必要的活动。