admin管理员组

文章数量:1399926

I am trying to build a cross-platform threaded timer function in C++. Here is what I have so far (posted also in Statically linked pthread and terminate called after throwing an instance of 'std::system_error')

main.cpp

#include <cinttypes>
#include <cstdlib>
#include <iostream>
#include <ostream>
#include <fstream>

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>

#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

//#define CHOSEN_CLOCK std::chrono::high_resolution_clock
#define CHOSEN_CLOCK std::chrono::steady_clock

// class Timer below derived from:
// .h
// /
// 


class Timer {
    std::atomic<bool> active{true};
  public:
    std::chrono::time_point<CHOSEN_CLOCK> timer_entry_ts; // SO:31497531
    template<typename Function>
    void setInterval(Function function, int interval);
    void stop();
};

template<typename Function>
void Timer::setInterval(Function function, int interval) {
  active = true;
  std::thread t([=]() {
    while(active.load()) {
      timer_entry_ts = CHOSEN_CLOCK::now();
      function();
      if(!active.load()) return;
      std::this_thread::sleep_until(timer_entry_ts + std::chrono::milliseconds(interval));
    }
  });
  t.detach();
}

void Timer::stop() {
  active = false;
}


Timer mtimer;
std::chrono::time_point<CHOSEN_CLOCK> last_entry_ts{};

void timer_function(void)
{
  long long int delta_micros = std::chrono::duration_cast<std::chrono::microseconds>(mtimer.timer_entry_ts-last_entry_ts).count();
  printf("%7.3f ms\n", delta_micros/1000.0f);
  last_entry_ts = mtimer.timer_entry_ts;
}

int main()
{
  last_entry_ts = CHOSEN_CLOCK::now();
  mtimer.setInterval(timer_function, 25); // repeat timer_function at 25 ms period
  std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // wait for 2 seconds
  mtimer.stop();
  printf("Thread stopped\n");

  std::exit(EXIT_SUCCESS);
}

Leaving aside issues like .join not being called (mentioned in OP), or that "In properly maintained C++ code std::thread::detach should not be used at all." - here I'm interested in the timing.

On Raspberry Pi Raspbian 9, I build this code with:

g++ -g -Wall -Wextra -std=gnu++11 ./main.cpp -o myProject.exe -pthread -lstdc++fs

... and when I run it, the timing (as indicated by printouts) appears very consistent and close to the required 25 ms (and this, even if I have a VNC connection in parallel to the headless Raspberry Pi, and if I'm trying to move around windows in the OS GUI at the same time):

$ ./myProject.exe
...
 25.080 ms
 25.107 ms
 25.100 ms
 25.108 ms
 25.099 ms
 25.104 ms
 25.121 ms
 25.122 ms
 25.112 ms
...

On Windows 10, with MINGW64 g++, I build this code with:

g++ -g -Wall -Wextra -std=gnu++11 ./main.cpp -o myProject.exe -lstdc++fs -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32

However, when I run the code, I never get 25 ms measurement, it's always at least 30 ms - and if I try to drag and move the adminitrative cmd window the program runs in, then I get up to 47 or so milliseconds:

C:\WINDOWS\system32>myProject.exe
...
 30.719 ms
 31.443 ms
 31.912 ms
 31.990 ms
 32.028 ms
 32.065 ms
 31.899 ms
 32.046 ms
 31.965 ms
 32.032 ms
 47.346 ms
 46.777 ms
 31.903 ms
 46.025 ms
 46.676 ms
 47.201 ms
 47.482 ms
 46.357 ms
 32.097 ms
...

And it's not that Windows 10 is incapable of reaching as low as 25 ms; if code is changed to mtimer.setInterval(timer_function, 15); instead, the results show clustering at either around 15 or 30 milliseconds (which I find strange):

...
 15.523 ms
 15.673 ms
 15.740 ms
 15.830 ms
 15.508 ms
 15.378 ms
 30.460 ms
 30.832 ms
 30.447 ms
 31.731 ms
 30.940 ms
 16.353 ms
...

Now, I am aware that in a preemptive operating system, you can never guarantee "absolutely" tight timing of a software timer - but then again, Raspbian 9 should also be a preemptive OS, and still the timing there (variance in 10s of microseconds for requested timer period in tens of milliseconds) is very satisfactory for me.

What can be changed in the code, so that also the Windows build of the program can show similar timing performance as the Linux/Raspbian one?

本文标签: multithreadingC thread timer function with consistent timing on WindowsStack Overflow