Linux C++ 用户空间应用程序实时睡眠功能(POSIX、Raspberry Pi)

Posted

技术标签:

【中文标题】Linux C++ 用户空间应用程序实时睡眠功能(POSIX、Raspberry Pi)【英文标题】:Linux C++ userspace app real time sleep function (POSIX, Raspberry Pi) 【发布时间】:2014-10-16 02:56:00 【问题描述】:

我需要一个在微秒内暂停我的程序的函数,它应该是实时的,所以如果我用 50微秒调用它,线程应该停止正好 50微秒。 我的 C++ 程序在安装了普通 Raspbian 的 Raspberry Pi 上运行。

我编写了这个示例程序,它使用 posix 时间函数来暂停测量暂停时间。

#include <cstdlib>
#include "stdint-gcc.h"
#include "signal.h"
#include <time.h>
#include <cerrno>
#include <cstdio>
#include <iostream>
#include <cstring>

#define S_IN_NS 1000000000UL
#define MS_IN_NS 1000000UL
#define US_IN_NS 1000UL
#define GET_TIME_CLOCK CLOCK_MONOTONIC

using namespace std;

int main(int argc, char** argv) 
    struct timespec newTimeStamp;
    struct timespec oldTimeStamp;
    struct timespec sleeptime;
    sleeptime.tv_sec = 0;
    sleeptime.tv_nsec = 50000; //50us

    if (clock_gettime(GET_TIME_CLOCK, &oldTimeStamp) == -1)
        cout << "Could not get clock time! ERRNO: " << strerror(errno);

    if ((clock_nanosleep(CLOCK_MONOTONIC, 0, &sleeptime, NULL)) == -1)
        cout << "Sleep failed! ERRNO: " << strerror(errno);


    if (clock_gettime(GET_TIME_CLOCK, &newTimeStamp) == -1)
        cout << "Could not get clock time! ERRNO: " << strerror(errno);

    uint64_t measuredSec = (newTimeStamp.tv_sec - oldTimeStamp.tv_sec);
    int32_t measuredNs = (newTimeStamp.tv_nsec - oldTimeStamp.tv_nsec);

    uint64_t diffus = (((measuredSec * S_IN_NS) + measuredNs + 500) / 1000UL);
    uint64_t diffns = (((measuredSec * S_IN_NS) + measuredNs));

    cout << "Diffns:" << diffns << " Diffus:" << diffus << endl;
    return 0;

构建命令:

arm-bcm2708hardfp-linux-gnueabi-g++ -lrt   -c -g -MMD -MP -MF "build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o.d" -o build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o main.cpp

arm-bcm2708hardfp-linux-gnueabi-g++ -lrt    -o dist/Debug/GNU_ARM_HARDFP-Linux-x86/timetest build/Debug/GNU_ARM_HARDFP-Linux-x86/main.o

结果(chrt - 操作进程的实时属性):

pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:130994 Diffus:131
pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:135994 Diffus:136
pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:138993 Diffus:139

程序应该正好休眠 50us,但我测量了 130-139us。 如果我将 GET_TIME_CLOCK 定义更改为 CLOCK_PROCESS_CPUTIME_ID,则会测量 CPU 时间(不包括睡眠时间)(据我所知)。

结果:

pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:89000 Diffus:89
pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:86000 Diffus:86
pi@raspberrypi ~ $ sudo chrt 99 ./timetest 
Diffns:88000 Diffus:88

即使我将睡眠时间更改为 500µs,执行 clock_nanosleep() 函数也需要大约 80-90µs!

那么有没有办法在 Raspbian 上的 C++ 用户空间应用程序中将线程挂起准确的时间 (µs)?

谢谢

【问题讨论】:

你能解释一下为什么你需要这样的功能吗?因为通常几乎总有比暂停一段时间更好的解决方案.. CLOCK_PROCESS_CPUTIME_ID 测量程序在 CPU 上花费的时间。无论您睡眠多长时间,您的程序都将使用相同数量的 CPU(因为睡眠不使用 CPU 时间)。使用chrt -f 1 ./timetest 可能会获得更准确的结果,但通常您需要实时操作系统以避免过多的抖动。 【参考方案1】:

如果您需要如此精确的睡眠时间,您可能需要使用旋转循环来检查当前时间。这将消耗相当多的电力(并产生热量),但这是一种相当可靠且便携的方式。另一个想法是尝试这个页面上的想法:http://blog.regehr.org/archives/794

【讨论】:

以上是关于Linux C++ 用户空间应用程序实时睡眠功能(POSIX、Raspberry Pi)的主要内容,如果未能解决你的问题,请参考以下文章

货物监控设备研发中,睡眠功能的应用

Linux时间子系统 用户空间接口函数

如何在Javascript中制作精确的睡眠功能,可能使用承诺?

《实时控制软件》第三周作业

Day7: Python学习笔记之Linux——系统监控

Linux下内存空间分配物理地址与虚拟地址映射