Stefan Jaritz
Stefan Jaritz

Reputation: 2279

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

I am playing around with monitoring stuff. For that I like to monitor pins etc. on a regular base. The monitoring app should run in user space and be written in C/C++. I am looking for a good practice how to approach this field of problems generally.

There is a good answer about using timers already here. My question is more general nature. Are timers the best solutions or maybe a wait for a semaphore with a timeout? etc.

I put some pseudo code as a base for the discussion:

// 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));
  }
}

I am looking for solutions, to sample signals etc. periodically, like to detect/measure the jitter in between two samples and use a function for obtaining the sample signal data.

Any ideas are welcome!

Upvotes: 2

Views: 7351

Answers (4)

user3629249
user3629249

Reputation: 16540

use the function: setitimer() here is simple example:

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);

And catch the timer on a regular interval by using struct sigaction.

Here is a simple example of using: struct sigaction:

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

and here is a simple implementation of the function: pSigHandler()

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

Of course, for all the above to work, need the two following statements:

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

There is a problem with the above code, There is a long list of functions that 'should' not be used in a signal handler. printf() is one of the problematic functions. My suggest is just have the signal handler function set a flag and the main function watching that flag and when found 'set', reset it and perform the necessary activities.

Upvotes: 3

Poeta Kodu
Poeta Kodu

Reputation: 1150

I won't impose how you should use threads, since this depends on your other code.
From C++11 there is a time manipulation module (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);

Upvotes: 1

SergeyA
SergeyA

Reputation: 62553

No. This is will not work for your purposes. Linux is no RTOS, and there is absolutely no guarantee what your process will be awaken at a requested time. It is not even a C++ question, it is an OS question.

The best way to achieve what you are doing on Linux I know of is to have a real-time process bound to isolated CPU, doing busy wait and waiting for a certain number of CPU cycles to pass before next sample.

Upvotes: 2

Johannes Overmann
Johannes Overmann

Reputation: 5131

You have to assume that the sleep() and also the "measuring of the monitoring time" is very imprecise.

If you would like to monitor things at regular intervals you have to change your code to wait until the next interesting point in time e.g.:

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);
    }
}

The most important point is to sleep/wait until the next absolute point in time, and to calculate this next absolute point in time solely based on your target interval, not based on any measured time or anything. This way any inaccuracies in sleep() and in execution time do not matter at all. In the code above you can replace the sleep() call with sleep((now - s.ts) / 2) and it will still hit the target frequency in the long run (just as an extreme example for a sleep implementation which only ever sleeps half as long as requested).

Upvotes: 1

Related Questions