diff --git a/example/example.vcxproj b/example/example.vcxproj
index 12cbcf6b..0cedd620 100644
--- a/example/example.vcxproj
+++ b/example/example.vcxproj
@@ -31,7 +31,7 @@
Application
true
- v120
+ v141
Unicode
@@ -43,7 +43,7 @@
Application
false
- v120
+ v141
true
Unicode
@@ -86,7 +86,7 @@
- Level4
+ Level3
Disabled
WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
..\include;%(AdditionalIncludeDirectories)
diff --git a/include/spdlog/async.h b/include/spdlog/async.h
index 469e47f1..2f4de8f3 100644
--- a/include/spdlog/async.h
+++ b/include/spdlog/async.h
@@ -38,17 +38,11 @@ struct async_factory_impl
template
static std::shared_ptr create(const std::string &logger_name, SinkArgs &&... args)
{
- using details::registry;
-
- std::lock_guard lock(registry::instance().tp_mutex());
- auto tp = registry::instance().get_thread_pool();
- if (tp == nullptr)
- {
- tp = std::make_shared(details::default_async_q_size, 1);
- registry::instance().set_thread_pool(tp);
- }
-
+ using details::registry;
auto sink = std::make_shared(std::forward(args)...);
+
+ // create default tp if not already exists.
+ auto tp = registry::instance().create_tp_once(details::default_async_q_size, 1);
auto new_logger = std::make_shared(logger_name, std::move(sink), std::move(tp), OverflowPolicy);
registry::instance().register_and_init(new_logger);
return new_logger;
@@ -72,16 +66,14 @@ inline std::shared_ptr create_async_nb(const std::string &logger
// set global thread pool.
inline void init_thread_pool(size_t q_size, size_t thread_count)
-{
- using details::registry;
- using details::thread_pool;
- auto tp = std::make_shared(q_size, thread_count);
- registry::instance().set_thread_pool(std::move(tp));
+{
+ auto tp = std::make_shared(q_size, thread_count);
+ details::registry::instance().set_tp(std::move(tp));
}
// get the global thread pool.
inline std::shared_ptr thread_pool()
{
- return details::registry::instance().get_thread_pool();
+ return details::registry::instance().get_tp();
}
} // namespace spdlog
diff --git a/include/spdlog/details/periodic_worker.h b/include/spdlog/details/periodic_worker.h
index 0fa55b89..96ec8db3 100644
--- a/include/spdlog/details/periodic_worker.h
+++ b/include/spdlog/details/periodic_worker.h
@@ -17,7 +17,6 @@
#include
#include
#include
-
namespace spdlog {
namespace details {
@@ -26,22 +25,19 @@ class periodic_worker
public:
periodic_worker(std::function callback_fun, std::chrono::seconds interval)
{
- if (interval == std::chrono::seconds::zero())
+ active_ = (interval > std::chrono::seconds::zero());
+ if (!active_)
{
- active_ = false;
return;
}
- active_ = true;
- flusher_thread_ = std::thread([callback_fun, interval, this]() {
+
+ worker_thread_ = std::thread([this, callback_fun, interval]() {
for (;;)
{
std::unique_lock lock(this->mutex_);
- bool should_terminate = this->cv_.wait_for(lock, interval, [this] {
- return !this->active_;
- });
- if (should_terminate)
+ if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
{
- break;
+ return; // active_ == false, so exit this thread
}
callback_fun();
}
@@ -51,24 +47,23 @@ public:
periodic_worker(const periodic_worker &) = delete;
periodic_worker &operator=(const periodic_worker &) = delete;
- // stop the back thread and join it
+ // stop the worker thread and join it
~periodic_worker()
{
- if (!active_)
- {
- return;
- }
- {
- std::lock_guard lock(mutex_);
- active_ = false;
- }
- cv_.notify_one();
- flusher_thread_.join();
+ if (worker_thread_.joinable())
+ {
+ {
+ std::lock_guard lock(mutex_);
+ active_ = false;
+ }
+ cv_.notify_one();
+ worker_thread_.join();
+ }
}
private:
bool active_;
- std::thread flusher_thread_;
+ std::thread worker_thread_;
std::mutex mutex_;
std::condition_variable cv_;
};
diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h
index bff70690..d5244ce3 100644
--- a/include/spdlog/details/registry.h
+++ b/include/spdlog/details/registry.h
@@ -24,18 +24,15 @@ namespace spdlog {
namespace details {
class thread_pool;
-template
-class registry_t
+class registry
{
public:
- using MutexT = Mutex;
-
- registry_t(const registry_t &) = delete;
- registry_t &operator=(const registry_t &) = delete;
+ registry(const registry &) = delete;
+ registry &operator=(const registry &) = delete;
void register_logger(std::shared_ptr new_logger)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
loggers_[logger_name] = new_logger;
@@ -43,7 +40,7 @@ public:
void register_and_init(std::shared_ptr new_logger)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
auto logger_name = new_logger->name();
throw_if_exists_(logger_name);
@@ -58,33 +55,44 @@ public:
new_logger->set_level(level_);
new_logger->flush_on(flush_level_);
- // Add to registry
+ // add to registry
loggers_[logger_name] = new_logger;
}
std::shared_ptr get(const std::string &logger_name)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
auto found = loggers_.find(logger_name);
return found == loggers_.end() ? nullptr : found->second;
}
- void set_thread_pool(std::shared_ptr tp)
+ void set_tp(std::shared_ptr tp)
{
- std::lock_guard lock(tp_mutex_);
+ std::lock_guard lock(tp_mutex_);
tp_ = std::move(tp);
}
- std::shared_ptr get_thread_pool()
+ // create tp only if not exists already
+ std::shared_ptr create_tp_once(size_t queue_size, size_t n_threads)
+ {
+ std::lock_guard lock(tp_mutex_);
+ if (tp_ == nullptr)
+ {
+ tp_ = std::make_shared(queue_size, n_threads);
+ }
+ return tp_;
+ }
+
+ std::shared_ptr get_tp()
{
- std::lock_guard lock(tp_mutex_);
+ std::lock_guard lock(tp_mutex_);
return tp_;
}
// Set global formatter. Each sink in each logger will get a clone of this object
void set_formatter(std::unique_ptr formatter)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
formatter_ = std::move(formatter);
for (auto &l : loggers_)
{
@@ -94,7 +102,7 @@ public:
void set_level(level::level_enum log_level)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_level(log_level);
@@ -104,7 +112,7 @@ public:
void flush_on(level::level_enum log_level)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->flush_on(log_level);
@@ -114,13 +122,14 @@ public:
void flush_every(std::chrono::seconds interval)
{
- std::lock_guard lock(loggers_mutex_);
- std::function clbk(std::bind(®istry_t::flush_all, this));
+ std::lock_guard lock(flusher_mutex_);
+ std::function clbk(std::bind(®istry::flush_all, this));
periodic_flusher_.reset(new periodic_worker(clbk, interval));
}
void set_error_handler(log_err_handler handler)
{
+ std::lock_guard lock(logger_map_mutex_);
for (auto &l : loggers_)
{
l.second->set_error_handler(handler);
@@ -130,52 +139,66 @@ public:
void apply_all(std::function)> fun)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
for (auto &l : loggers_)
{
fun(l.second);
}
}
+ void flush_all()
+ {
+ std::lock_guard lock(logger_map_mutex_);
+ for (auto &l : loggers_)
+ {
+ l.second->flush();
+ }
+ }
+
void drop(const std::string &logger_name)
{
- std::lock_guard lock(loggers_mutex_);
+ std::lock_guard lock(logger_map_mutex_);
loggers_.erase(logger_name);
}
void drop_all()
+ {
+ std::lock_guard lock(logger_map_mutex_);
+ loggers_.clear();
+ }
+
+ // clean all reasources and threads started by the registry
+ void shutdown()
{
{
- std::lock_guard lock(loggers_mutex_);
- loggers_.clear();
+ std::lock_guard lock(flusher_mutex_);
+ periodic_flusher_.reset();
}
+ drop_all();
+
{
- std::lock_guard lock(tp_mutex_);
+ std::lock_guard lock(tp_mutex_);
tp_.reset();
}
}
-
- std::recursive_mutex &tp_mutex()
+
+ static registry &instance()
{
- return tp_mutex_;
- }
-
- static registry_t &instance()
- {
- static registry_t s_instance;
+ static registry s_instance;
return s_instance;
}
private:
- registry_t()
+ registry()
: formatter_(new pattern_formatter("%+"))
{
}
- ~registry_t()
+ ~registry()
{
- periodic_flusher_.reset();
+ /*std::lock_guard lock(flusher_mutex_);
+ periodic_flusher_.reset();*/
}
void throw_if_exists_(const std::string &logger_name)
@@ -185,20 +208,10 @@ private:
throw spdlog_ex("logger with name '" + logger_name + "' already exists");
}
}
-
- void flush_all()
- {
- std::lock_guard lock(loggers_mutex_);
- for (auto &l : loggers_)
- {
- l.second->flush();
- }
- }
-
- Mutex loggers_mutex_;
- std::recursive_mutex tp_mutex_;
- std::unordered_map> loggers_;
- // std::unique_ptr formatter_{ new pattern_formatter("%+") };
+
+ std::mutex logger_map_mutex_, flusher_mutex_;
+ std::mutex tp_mutex_;
+ std::unordered_map> loggers_;
std::unique_ptr formatter_;
level::level_enum level_ = level::info;
level::level_enum flush_level_ = level::off;
@@ -207,13 +220,5 @@ private:
std::unique_ptr periodic_flusher_;
};
-#ifdef SPDLOG_NO_REGISTRY_MUTEX
-#include "spdlog/details/null_mutex.h"
-using registry = registry_t;
-#else
-#include
-using registry = registry_t;
-#endif
-
} // namespace details
} // namespace spdlog
diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h
index cc039062..cf4cac2d 100644
--- a/include/spdlog/spdlog.h
+++ b/include/spdlog/spdlog.h
@@ -117,6 +117,12 @@ inline void drop_all()
details::registry::instance().drop_all();
}
+// stop any running threads started by spdlog and clean registry loggers
+void shutdown()
+{
+ details::registry::instance().shutdown();
+}
+
///////////////////////////////////////////////////////////////////////////////
//
// Trace & Debug can be switched on/off at compile time for zero cost debug
diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h
index 1eb26cd2..53256450 100644
--- a/include/spdlog/tweakme.h
+++ b/include/spdlog/tweakme.h
@@ -68,15 +68,6 @@
// #define SPDLOG_TRACE_ON
///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-// Uncomment to avoid locking in the registry operations (spdlog::get(),
-// spdlog::drop() spdlog::register()).
-// Use only if your code never modifies concurrently the registry.
-// Note that upon creating a logger the registry is modified by spdlog..
-//
-// #define SPDLOG_NO_REGISTRY_MUTEX
-///////////////////////////////////////////////////////////////////////////////
-
///////////////////////////////////////////////////////////////////////////////
// Uncomment to avoid spdlog's usage of atomic log levels
// Use only if your code never modifies a logger's log levels concurrently by
diff --git a/tests/tests.vcxproj.user b/tests/tests.vcxproj.user
new file mode 100644
index 00000000..be250787
--- /dev/null
+++ b/tests/tests.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file