Skip to content

Instantly share code, notes, and snippets.

@kbridge
Created August 30, 2019 09:40
Show Gist options
  • Save kbridge/251808f0cb7411782c3a2ce5f4877287 to your computer and use it in GitHub Desktop.
Save kbridge/251808f0cb7411782c3a2ce5f4877287 to your computer and use it in GitHub Desktop.
spdlog periodic_worker workaround for MSVC
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
#ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/periodic_worker.h"
#endif
namespace spdlog {
namespace details {
SPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
{
#ifdef _WIN32
::InitializeCriticalSection(&cs_);
::InitializeConditionVariable(&cv_);
#endif
active_ = (interval > std::chrono::seconds::zero());
if (!active_)
{
return;
}
worker_thread_ = std::thread([this, callback_fun, interval]() {
for (;;)
{
#ifdef _WIN32
::EnterCriticalSection(&cs_);
if (!active_)
{
::LeaveCriticalSection(&cs_);
return;
}
else
{
SleepConditionVariableCS(&cv_, &cs_, static_cast<DWORD>(interval.count()) * 1000);
if (!active_)
{
::LeaveCriticalSection(&cs_);
return;
}
// TODO if not timed-out, sleep more
}
callback_fun();
::LeaveCriticalSection(&cs_);
#else
std::unique_lock<std::mutex> lock(this->mutex_);
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
{
return; // active_ == false, so exit this thread
}
callback_fun();
#endif
}
});
}
// stop the worker thread and join it
SPDLOG_INLINE periodic_worker::~periodic_worker()
{
if (worker_thread_.joinable())
{
#ifdef _WIN32
{
::EnterCriticalSection(&cs_);
active_ = false;
::LeaveCriticalSection(&cs_);
}
WakeConditionVariable(&cv_);
#else
{
std::lock_guard<std::mutex> lock(mutex_);
active_ = false;
}
cv_.notify_one();
#endif
worker_thread_.join();
}
#ifdef _WIN32
::DeleteCriticalSection(&cs_);
#endif
}
} // namespace details
} // namespace spdlog
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// periodic worker thread - periodically executes the given callback function.
//
// RAII over the owned thread:
// creates the thread on construction.
// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
namespace spdlog {
namespace details {
class periodic_worker
{
public:
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);
periodic_worker(const periodic_worker &) = delete;
periodic_worker &operator=(const periodic_worker &) = delete;
// stop the worker thread and join it
~periodic_worker();
private:
bool active_;
std::thread worker_thread_;
#ifdef _WIN32
CRITICAL_SECTION cs_;
CONDITION_VARIABLE cv_;
#else
std::mutex mutex_;
std::condition_variable cv_;
#endif
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "periodic_worker-inl.h"
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment