提供された関数を周期的に実行するクラスを実装しました。
//Timer.h
#include <chrono>
#include <mutex>
#include <thread>
class Timer {
public:
Timer(const std::chrono::milliseconds period, const std::function<void()>& handler);
~Timer();
void Start();
void Stop();
bool IsRunning() const;
private:
const std::function<void()>& handler;
const std::chrono::milliseconds period;
bool isRunning = false;
mutable std::recursive_mutex lock;
int counter = 0;
void DoLoop(int id);
};
//Timer.cpp
#include "Timer.h"
Timer::Timer(const std::chrono::milliseconds period, const std::function<void()>& handler) :handler(handler), period(period), lock(){}
Timer::~Timer() {
Stop();
}
void Timer::Stop() {
lock.lock();
isRunning = false;
lock.unlock();
}
void Timer::Start() {
lock.lock();
if (!isRunning) {
isRunning = true;
counter++;
std::thread(&Timer::DoLoop, this, counter).detach();
}
lock.unlock();
}
void Timer::DoLoop(int id) {
while (true){
std::this_thread::sleep_for(period);
lock.lock();
bool goOn = isRunning && counter==id;
if (goOn) std::thread(handler).detach();
lock.unlock();
if (!goOn)
break;
}
}
bool Timer::IsRunning() const {
lock.lock();
bool isRunning = this->isRunning;
lock.unlock();
return isRunning;
}
そして、これが機能するかどうかを確認するための簡単なプログラムです。
void Tick(){ cout << "TICK" << endl; }
int main() {
Timer timer(milliseconds(1000), Tick);
timer.Start();
cin.get();
}
g++ でアプリをビルドすると、プログラムは問題なくビルドおよび実行されます。ただし、Microsoft のコンパイラ (v18) を使用すると、プログラムもコンパイルされますが、実行時に失敗します。
リリース構成を使用すると、スレッドの 1 つから次の例外が発生します。
Program.exe の 0x000007F8D8E14A30 (msvcr120.dll) で未処理の例外: 致命的なプログラムの終了が要求されました。
デバッグ構成を使用すると、Microsoft Visual C++ ランタイム ライブラリ エラーが毎秒表示されます。
デバッグ エラー!
プログラム: ...\path\Program.exe
R6010 - abort() が呼び出されました
両方の構成で:
タイマーのループの 2 回目の反復で、例外がスローされるか、エラーが発生し始めます。
呼び出されても、プログラムは
Tick
関数に一度も入りません。thread(handler)
エラー発生時のスタック トレースはこれら 2 つの構成で異なりますが、どちらにも私のコードからの情報は含まれていません。
ntdll.dll!UserThreadStart()
どちらも;で始まります。デバッグは で終わりmsvcr123d.dll!_NMSG_WRITE()
、リリースは で終わりmsvcr120.dll!abort()
ます。
問題が発生するのはなぜですか?また、アプリが MSVC でコンパイルされている場合にのみ発生するのはなぜですか? それはある種のMSVCのバグですか?それとも、コンパイラの構成で何かを変更する必要がありますか?