使用MSVC编译的多线程应用程序在运行时失败

时间:2015-02-25 11:51:11

标签: c++ c++11 visual-c++ gcc cl

我实现了一个循环运行提供函数的类。

//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)时,程序也会编译,但它在运行时失败。

当我使用发布配置时,我从其中一个线程获得以下异常:

  

Program.exe中0x000007F8D8E14A30(msvcr120.dll)的未处理异常:请求致命程序退出。

当我使用调试配置时,每秒都会弹出Microsoft Visual C ++运行时库错误:

  

调试错误!

     

程序:... \ path \ Program.exe

     

R6010    - abort()被称为

在两种配置中:

  • 抛出异常/错误在计时器循环的第二次迭代中开始弹出。

  • 即使Tick被调用,该程序也不会进入thread(handler)函数。

  • 虽然错误时刻的堆栈跟踪在这两种配置中有所不同,但它们都不包含我的代码中的任何内容。两者都以ntdll.dll!UserThreadStart()开头;调试以msvcr123d.dll!_NMSG_WRITE()结尾,版本以msvcr120.dll!abort()结尾。

为什么只有在使用MSVC编译应用程序时才出现问题?这是某种MSVC的错误吗?或者我应该在编译器的配置中改变一些东西?

1 个答案:

答案 0 :(得分: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调用后,函数对象被破坏了。不知道为什么会这样。