Я реализовал класс, который циклически запускает предоставленную функцию.
//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), программа также компилируется, но происходит сбой во время выполнения.
Когда я использую конфигурацию выпуска, я получаю следующее исключение из одного из потоков:
Необработанное исключение по адресу 0x000007F8D8E14A30 (msvcr120.dll) в Program.exe: запрошен фатальный выход из программы.
Когда я использую конфигурацию отладки, каждую секунду появляется ошибка библиотеки времени выполнения Microsoft Visual C++:
Ошибка отладки!
Программа: ...\путь\Program.exe
R6010 - был вызван abort()
В обеих конфигурациях:
Исключение выдается/ошибки начинают появляться на второй итерации цикла таймера.
Программа ни разу не заходит в функцию
Tick
, хотя вызываетсяthread(handler)
.Хотя трассировки стека на момент ошибки различаются в этих двух конфигурациях, ни одна из них не содержит ничего из моего кода. Оба начинаются с
ntdll.dll!UserThreadStart()
; отладочная заканчивается наmsvcr123d.dll!_NMSG_WRITE()
, а релизная — наmsvcr120.dll!abort()
.
Почему возникают проблемы и почему только тогда, когда приложение скомпилировано с помощью MSVC? Это какая-то ошибка MSVC? Или, может быть, я должен что-то изменить в конфигурации компилятора?
Stop()
должен останавливать таймер от новых вызовов, а не прекращать все действия, начатые таймером. Кроме того, если бы я хотел дождаться завершения вызова, я должен был бы накапливать ссылки на все запущенные потоки, потому что те, которые были запущены ранее, могли еще работать. - person tearvisus   schedule 25.02.2015lock()
иunlock()
вручную, вместо этого используйтеstd::lock_guard
. Прямо сейчас, если что-то вызовет исключение внутри ваших замков, вы зайдете в тупик. - person Mgetz   schedule 25.02.2015lock_guard
кажется идеальным решением. - person tearvisus   schedule 25.02.2015