4

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();
    cin.get();
}

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 anything 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?

4

1 回答 1

3

您的线程正在抛出std::bad_function_call,未处理异常,因此运行时正在调用abort()

改变:

const std::function<void()>& handler;

const std::function<void()> handler;

修复问题。我想这是因为你在线程之间共享它?

如果您创建本地并传递对它的引用,也可以使用:

  const std::function<void()> f = Tick;
  Timer timer(std::chrono::milliseconds(1000), f);

所以它一定以某种方式超出了范围。

编辑:确实,函数对象在 ctor 调用后被破坏。不知道为什么会这样。

于 2015-02-25T13:31:48.907 回答