mercredi 25 février 2015

A multithreading app compiled with MSVC fails at runtime

I've implemented a class that cyclically runs a supplied function.



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


And here'a s simple program to see if it works:



void Tick(){ cout << "TICK" << endl; }

int main() {
Timer timer(milliseconds(1000), Tick);
timer.Start();
}


When I build the app with g++, the program builds and runs without any problems. However, when I use the Microsoft's compiler (v18) the program compiles as well, but it fails at runtime.


When I use the release configuration I get the following exception from one of the threads:



Unhandled exception at 0x000007F8D8E14A30 (msvcr120.dll) in Program.exe: Fatal program exit requested.



When I use the debug configuration, a Microsoft Visual C++ Runtime Library error pops up every second:



Debug Error!


Program: ...\path\Program.exe


R6010 - abort() has been called



In both configurations:




  • The exception is thrown/the errors start popping up in the second iteration of the timer's loop.




  • The program does not enter the Tick function even once, even though thread(handler) gets invoked.




  • Although the stack traces at the moment of error differ in those two configurations, neither of them contains nothing from my code. Both start with ntdll.dll!UserThreadStart(); the debug one ends with msvcr123d.dll!_NMSG_WRITE() and the release one ends with msvcr120.dll!abort().




Why do the problems appear and why only when the app is compiled with MSVC? Is it some kind of MSVC's bug? Or maybe should I change something in the compiler's configuration?


Aucun commentaire:

Enregistrer un commentaire