From 26c93dc061558c3cc4137e262eafd028e70d74aa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 16 Aug 2024 16:19:03 +0300 Subject: [PATCH] Replaced Boost.Thread synchronization primitives with std equivalents. This replaces boost::thread and most mutexes and condition variables with std equivalents. It also adds support for std lock types to the strictest_lock type trait. This significantly, although not completely, reduces the dependency on Boost.Thread. Refs https://github.com/boostorg/log/issues/232. --- build/Jamfile.v2 | 4 + doc/changelog.qbk | 9 ++ example/advanced_usage/Jamfile.v2 | 1 - example/async_log/Jamfile.v2 | 1 - example/async_log/main.cpp | 24 +++-- example/basic_usage/Jamfile.v2 | 1 - example/bounded_async_log/Jamfile.v2 | 1 - example/bounded_async_log/main.cpp | 24 +++-- example/doc/extension_app_launcher.cpp | 4 +- example/doc/extension_record_tagger.cpp | 4 +- example/doc/sinks_async_ordering.cpp | 4 +- example/doc/util_dynamic_type_disp.cpp | 4 + example/doc/util_static_type_disp.cpp | 4 + example/event_log/Jamfile.v2 | 1 - example/keywords/Jamfile.v2 | 1 - example/multiple_files/Jamfile.v2 | 1 - example/multiple_files/main.cpp | 13 +-- example/multiple_threads/Jamfile.v2 | 1 - example/multiple_threads/main.cpp | 19 ++-- example/native_syslog/Jamfile.v2 | 1 - example/rotating_file/Jamfile.v2 | 1 - example/settings_file/Jamfile.v2 | 1 - .../settings_file_custom_factories/Jamfile.v2 | 1 - example/syslog/Jamfile.v2 | 1 - example/trivial/Jamfile.v2 | 1 - example/wide_char/Jamfile.v2 | 1 - include/boost/log/detail/adaptive_mutex.hpp | 18 ++-- include/boost/log/detail/enqueued_record.hpp | 6 +- include/boost/log/detail/event.hpp | 10 +-- include/boost/log/detail/locking_ptr.hpp | 4 +- include/boost/log/detail/locks.hpp | 31 +++++++ include/boost/log/sinks/async_frontend.hpp | 51 +++++------ .../boost/log/sinks/basic_sink_frontend.hpp | 33 ------- include/boost/log/sinks/block_on_overflow.hpp | 4 +- .../boost/log/sinks/bounded_fifo_queue.hpp | 19 ++-- .../log/sinks/bounded_ordering_queue.hpp | 50 +++++------ include/boost/log/sinks/sync_frontend.hpp | 4 +- .../log/sinks/unbounded_ordering_queue.hpp | 50 +++++------ .../log/sources/exception_handler_feature.hpp | 15 ---- include/boost/log/utility/strictest_lock.hpp | 31 +++++++ src/core.cpp | 44 +-------- src/default_sink.cpp | 6 +- src/default_sink.hpp | 4 +- src/event.cpp | 6 +- src/global_logger_storage.cpp | 7 +- src/once_block.cpp | 15 ++-- src/setup/init_from_settings.cpp | 2 +- src/syslog_backend.cpp | 17 ++-- src/text_file_backend.cpp | 17 ++-- src/thread_id.cpp | 2 +- src/timer.cpp | 7 +- test/Jamfile.v2 | 1 - test/common/test_barrier.hpp | 62 +++++++++++++ test/performance/record_emission.cpp | 34 ++++--- test/run/core.cpp | 4 +- test/run/util_ipc_reliable_mq.cpp | 23 +++-- test/run/util_once_block.cpp | 89 ++++++++++--------- 57 files changed, 407 insertions(+), 387 deletions(-) create mode 100644 test/common/test_barrier.hpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 4657fdfb14..dfb6a65a4a 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -132,6 +132,10 @@ project boost/log : usage-requirements clang:-Wno-bind-to-temporary-copy clang:-Wno-unused-function + + single:BOOST_LOG_NO_THREADS + multi:/boost/atomic//boost_atomic + multi:/boost/thread//boost_thread ; local BOOST_LOG_COMMON_SRC = diff --git a/doc/changelog.qbk b/doc/changelog.qbk index f3d937bc72..15fe4c29a8 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,15 @@ [section:changelog Changelog] +[heading 2.30, Boost 1.87] + +* Replaced __boost_thread__ synchronization primitives with equivalents from the C++ standard library. This may improve multithreaded performance, but also has user-facing consequences: + * __boost_thread__ thread interruption is no longer supported. Boost.Log no longer has special treatment for the `thread_interrupted` exception that is used by Boost.Thread to implement thread interruption. This exception will be handled like any other exception. + In particular, user-specified exception handlers may now be invoked with the `thread_interrupted` pending exception. + * For timed waiting operations, timeouts are now using std::chrono time units. This means that the `ordering_window` named parameter that is supported by the [class_sinks_bounded_ordering_queue] and [class_sinks_unbounded_ordering_queue] now expects an `std::chrono::duration` value instead of `boost::posix_time::time_duration` from __boost_date_time__. + * In case of errors indicated by thread synchronization primitives, `std::system_error` exception is thrown instead of __boost_thread__ exception types. +* Added support for C++ standard library lock types to [class_log_strictest_lock]. + [heading 2.29, Boost 1.86] * Added a workaround for `windres.exe` issue, when it is used in CMake to compile event log resource files on MinGW-w64. ([pull_request 231]) diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index 7fd1692335..2bebc7a6a1 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index d8506ff24d..393086ff4f 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/async_log/main.cpp b/example/async_log/main.cpp index 7f7a19509f..99a0687382 100644 --- a/example/async_log/main.cpp +++ b/example/async_log/main.cpp @@ -15,16 +15,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include -#include #include #include -#include -#include +#include #include #include @@ -51,13 +48,13 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Here we go. First, identify the thread. - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -95,7 +92,7 @@ int main(int argc, char* argv[]) expr::format("%1%: [%2%] [%3%] - %4%") % expr::attr< unsigned int >("RecordID") % expr::attr< boost::posix_time::ptime >("TimeStamp") - % expr::attr< boost::thread::id >("ThreadID") + % expr::attr< std::thread::id >("ThreadID") % expr::smessage ); @@ -107,13 +104,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); // Flush all buffered records sink->stop(); diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index ea7dab52e9..8f4acd7dd5 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe basic_usage diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index 052aabab04..4ed0294b3d 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/bounded_async_log/main.cpp b/example/bounded_async_log/main.cpp index 50e347d328..9bbd8cc86a 100644 --- a/example/bounded_async_log/main.cpp +++ b/example/bounded_async_log/main.cpp @@ -15,16 +15,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include -#include #include #include -#include -#include +#include #include #include @@ -51,13 +48,13 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Here we go. First, identify the thread. - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -97,7 +94,7 @@ int main(int argc, char* argv[]) expr::format("%1%: [%2%] [%3%] - %4%") % expr::attr< unsigned int >("RecordID") % expr::attr< boost::posix_time::ptime >("TimeStamp") - % expr::attr< boost::thread::id >("ThreadID") + % expr::attr< std::thread::id >("ThreadID") % expr::smessage ); @@ -109,13 +106,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); // Flush all buffered records sink->stop(); diff --git a/example/doc/extension_app_launcher.cpp b/example/doc/extension_app_launcher.cpp index eafa0bd044..a72e1a4a39 100644 --- a/example/doc/extension_app_launcher.cpp +++ b/example/doc/extension_app_launcher.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,8 @@ class app_launcher : // The function consumes the log records that come from the frontend void app_launcher::consume(logging::record_view const& rec, string_type const& command_line) { - std::system(command_line.c_str()); + int res = std::system(command_line.c_str()); + boost::ignore_unused(res); } //] diff --git a/example/doc/extension_record_tagger.cpp b/example/doc/extension_record_tagger.cpp index 99cc7cd0db..e7fbfbf52a 100644 --- a/example/doc/extension_record_tagger.cpp +++ b/example/doc/extension_record_tagger.cpp @@ -5,6 +5,7 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#include #include #include #include @@ -13,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -65,7 +65,7 @@ class record_tagger_feature : // The method will require locking, so we have to define locking requirements for it. // We use the strictest_lock trait in order to choose the most restricting lock type. typedef typename logging::strictest_lock< - boost::lock_guard< threading_model >, + std::lock_guard< threading_model >, typename BaseT::open_record_lock, typename BaseT::add_attribute_lock, typename BaseT::remove_attribute_lock diff --git a/example/doc/sinks_async_ordering.cpp b/example/doc/sinks_async_ordering.cpp index 3f72ee8499..3c2fd10663 100644 --- a/example/doc/sinks_async_ordering.cpp +++ b/example/doc/sinks_async_ordering.cpp @@ -5,13 +5,13 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#include #include #include #include #include #include #include -#include #include #include #include @@ -62,7 +62,7 @@ boost::shared_ptr< sink_t > init_logging() backend, /*< pointer to the pre-initialized backend >*/ keywords::order = logging::make_attr_ordering< unsigned int >( /*< log record ordering predicate >*/ "LineID", std::less< unsigned int >()), - keywords::ordering_window = boost::posix_time::seconds(1) /*< latency of log record processing >*/ + keywords::ordering_window = std::chrono::seconds(1) /*< latency of log record processing >*/ )); core->add_sink(sink); diff --git a/example/doc/util_dynamic_type_disp.cpp b/example/doc/util_dynamic_type_disp.cpp index 7f0e3caf3d..b0ad722700 100644 --- a/example/doc/util_dynamic_type_disp.cpp +++ b/example/doc/util_dynamic_type_disp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace logging = boost::log; @@ -85,13 +86,16 @@ int main(int, char*[]) // These two attributes are supported by the dispatcher bool res = print(my_value< std::string >("Hello world!")); assert(res); + boost::ignore_unused(res); res = print(my_value< double >(1.2)); assert(res); + boost::ignore_unused(res); // This one is not res = print(my_value< float >(-4.3f)); assert(!res); + boost::ignore_unused(res); return 0; } diff --git a/example/doc/util_static_type_disp.cpp b/example/doc/util_static_type_disp.cpp index a0adda130e..82862c6d31 100644 --- a/example/doc/util_static_type_disp.cpp +++ b/example/doc/util_static_type_disp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -82,13 +83,16 @@ int main(int, char*[]) // These two attributes are supported by the dispatcher bool res = print(my_value< std::string >("Hello world!")); assert(res); + boost::ignore_unused(res); res = print(my_value< double >(1.2)); assert(res); + boost::ignore_unused(res); // This one is not res = print(my_value< float >(-4.3f)); assert(!res); + boost::ignore_unused(res); return 0; } diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index d876ec7a73..ab80036d4f 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -79,7 +79,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index b53e1ede47..5742e17325 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe keywords diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index 3edecd7ac2..a3f2d3f274 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/multiple_files/main.cpp b/example/multiple_files/main.cpp index 0a1ce47d54..3605d6736d 100644 --- a/example/multiple_files/main.cpp +++ b/example/multiple_files/main.cpp @@ -19,10 +19,10 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include #include #include @@ -53,7 +53,7 @@ BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt) // This function is executed in a separate thread void thread_foo() { - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) { BOOST_LOG(my_logger::get()) << "Log record " << i; @@ -70,7 +70,7 @@ int main(int argc, char* argv[]) // Set up how the file names will be generated sink->locked_backend()->set_file_name_composer(sinks::file::as_file_name_composer( - expr::stream << "logs/" << expr::attr< boost::thread::id >("ThreadID") << ".log")); + expr::stream << "logs/" << expr::attr< std::thread::id >("ThreadID") << ".log")); // Set the log record formatter sink->set_formatter @@ -89,11 +89,12 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create threads and make some logs - boost::thread_group threads; + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(&thread_foo); + threads[i] = std::thread(&thread_foo); - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); return 0; } diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 6e1c9b70ee..330f1276e3 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/multiple_threads/main.cpp b/example/multiple_threads/main.cpp index 2b005237ff..44f3640110 100644 --- a/example/multiple_threads/main.cpp +++ b/example/multiple_threads/main.cpp @@ -18,15 +18,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include #include #include -#include -#include +#include #include #include @@ -52,10 +50,10 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -97,13 +95,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("ThreadID", attrs::current_thread_id()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); return 0; } diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index 293d6900b8..de6c572a77 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index 4ea7f656fb..32f62ed9ab 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index 0eec5cf665..fc4af4d96b 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe settings_file diff --git a/example/settings_file_custom_factories/Jamfile.v2 b/example/settings_file_custom_factories/Jamfile.v2 index 7c682a057e..72edb991b1 100644 --- a/example/settings_file_custom_factories/Jamfile.v2 +++ b/example/settings_file_custom_factories/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe settings_file_custom_factories diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index 3ed4362e55..4c8d181847 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 1d89159ff1..aef9de78e8 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -42,7 +42,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe trivial diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index dab6836fe7..2a7477d6cf 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem /boost/locale//boost_locale - /boost/thread//boost_thread multi # does not build on VxWorks due to lack of boost::locale support diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index acfc5f3cf0..fa06a0bdbf 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -24,10 +24,6 @@ #ifndef BOOST_LOG_NO_THREADS -#include -#include -#include - #if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD #elif defined(BOOST_WINDOWS) @@ -144,7 +140,10 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #elif defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD) #include +#include +#include #include +#include #include #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) @@ -177,7 +176,7 @@ class adaptive_mutex const int err = pthread_mutex_init(&m_State, NULL); #endif if (BOOST_UNLIKELY(err != 0)) - throw_exception< thread_resource_error >(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__); + throw_system_error(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__); } ~adaptive_mutex() @@ -191,7 +190,7 @@ class adaptive_mutex if (err == 0) return true; if (BOOST_UNLIKELY(err != EBUSY)) - throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__); + throw_system_error(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__); return false; } @@ -199,7 +198,7 @@ class adaptive_mutex { const int err = pthread_mutex_lock(&m_State); if (BOOST_UNLIKELY(err != 0)) - throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__); + throw_system_error(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__); } void unlock() @@ -212,10 +211,9 @@ class adaptive_mutex BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&)) private: - template< typename ExceptionT > - static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_exception(int err, const char* descr, const char* func, const char* file, int line) + static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_system_error(int err, const char* descr, const char* func, const char* file, int line) { - boost::throw_exception(ExceptionT(err, descr), boost::source_location(file, line, func)); + boost::throw_exception(std::system_error(std::error_code(err, std::system_category()), descr), boost::source_location(file, line, func)); } }; diff --git a/include/boost/log/detail/enqueued_record.hpp b/include/boost/log/detail/enqueued_record.hpp index a5c6e01811..e1926a68bf 100644 --- a/include/boost/log/detail/enqueued_record.hpp +++ b/include/boost/log/detail/enqueued_record.hpp @@ -17,10 +17,10 @@ #ifndef BOOST_LOG_DETAIL_ENQUEUED_RECORD_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_ENQUEUED_RECORD_HPP_INCLUDED_ +#include #include #include #include -#include #include #include @@ -60,7 +60,7 @@ class enqueued_record } }; - boost::log::aux::timestamp m_timestamp; + std::chrono::steady_clock::time_point m_timestamp; record_view m_record; enqueued_record(enqueued_record const& that) BOOST_NOEXCEPT : m_timestamp(that.m_timestamp), m_record(that.m_record) @@ -72,7 +72,7 @@ class enqueued_record { } explicit enqueued_record(record_view const& rec) : - m_timestamp(boost::log::aux::get_timestamp()), + m_timestamp(std::chrono::steady_clock::now()), m_record(rec) { } diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index ff9951af26..05716d1c33 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -37,9 +37,9 @@ #include #define BOOST_LOG_EVENT_USE_WINAPI #else -#include -#include -#define BOOST_LOG_EVENT_USE_BOOST_CONDITION_VARIABLE +#include +#include +#define BOOST_LOG_EVENT_USE_STD_CONDITION_VARIABLE #endif #include @@ -130,8 +130,8 @@ typedef winapi_based_event event; class generic_event { private: - boost::mutex m_mutex; - boost::condition_variable m_cond; + std::mutex m_mutex; + std::condition_variable m_cond; bool m_state; public: diff --git a/include/boost/log/detail/locking_ptr.hpp b/include/boost/log/detail/locking_ptr.hpp index 7790c4dceb..1596ad13ab 100644 --- a/include/boost/log/detail/locking_ptr.hpp +++ b/include/boost/log/detail/locking_ptr.hpp @@ -17,9 +17,9 @@ #define BOOST_LOG_DETAIL_LOCKING_PTR_HPP_INCLUDED_ #include +#include // try_to_lock_t #include #include -#include #include #include #include @@ -66,7 +66,7 @@ class locking_ptr m_pLock->lock(); } //! Constructor - locking_ptr(shared_ptr< element_type > const& p, lockable_type& l, try_to_lock_t const&) : m_pElement(p), m_pLock(&l) + locking_ptr(shared_ptr< element_type > const& p, lockable_type& l, std::try_to_lock_t) : m_pElement(p), m_pLock(&l) { if (!m_pLock->try_lock()) { diff --git a/include/boost/log/detail/locks.hpp b/include/boost/log/detail/locks.hpp index fcc32a2c68..c5aae25568 100644 --- a/include/boost/log/detail/locks.hpp +++ b/include/boost/log/detail/locks.hpp @@ -17,6 +17,37 @@ #define BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_ #include + +#ifndef BOOST_LOG_NO_THREADS + +#include +BOOST_MOVE_STD_NS_BEG + +// Forward declaration of the standard locks. Specified to avoid including and . +#if !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename > +class lock_guard; +#else +// MSVC 14.0 has a non-confogrming lock_guard +template< typename... > +class lock_guard; +#endif +template< typename > +class unique_lock; +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) +template< typename > +class shared_lock; +#endif +#if defined(__cpp_lib_scoped_lock) && (__cpp_lib_scoped_lock >= 201703l) +template< typename... > +class scoped_lock; +#endif + +BOOST_MOVE_STD_NS_END +#include + +#endif // BOOST_LOG_NO_THREADS + #include #ifdef BOOST_HAS_PRAGMA_ONCE diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 79fade5b68..3e4a1d77da 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -15,6 +15,9 @@ #ifndef BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_ +#include +#include +#include #include // std::terminate #include @@ -32,10 +35,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -133,7 +132,7 @@ class asynchronous_sink : private: //! Backend synchronization mutex type - typedef boost::recursive_mutex backend_mutex_type; + typedef std::recursive_mutex backend_mutex_type; //! Frontend synchronization mutex type typedef typename base_type::mutex_type frontend_mutex_type; @@ -191,11 +190,11 @@ class asynchronous_sink : { private: frontend_mutex_type& m_Mutex; - condition_variable_any& m_Cond; + std::condition_variable_any& m_Cond; boost::atomic< bool >& m_Flag; public: - explicit scoped_flag(frontend_mutex_type& mut, condition_variable_any& cond, boost::atomic< bool >& f) : + explicit scoped_flag(frontend_mutex_type& mut, std::condition_variable_any& cond, boost::atomic< bool >& f) : m_Mutex(mut), m_Cond(cond), m_Flag(f) { } @@ -203,7 +202,7 @@ class asynchronous_sink : { try { - lock_guard< frontend_mutex_type > lock(m_Mutex); + std::lock_guard< frontend_mutex_type > lock(m_Mutex); m_Flag.store(false, boost::memory_order_relaxed); m_Cond.notify_all(); } @@ -242,9 +241,9 @@ class asynchronous_sink : const shared_ptr< sink_backend_type > m_pBackend; //! Dedicated record feeding thread - thread m_DedicatedFeedingThread; + std::thread m_DedicatedFeedingThread; //! Condition variable to implement blocking operations - condition_variable_any m_BlockCond; + std::condition_variable_any m_BlockCond; //! Currently active operation operation m_ActiveOperation; @@ -318,15 +317,7 @@ class asynchronous_sink : */ ~asynchronous_sink() BOOST_NOEXCEPT BOOST_OVERRIDE { - try - { - boost::this_thread::disable_interruption no_interrupts; - stop(); - } - catch (...) - { - std::terminate(); - } + stop(); } /*! @@ -344,7 +335,7 @@ class asynchronous_sink : { if (BOOST_UNLIKELY(m_FlushRequested.load(boost::memory_order_acquire))) { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); // Wait until flush is done while (m_FlushRequested.load(boost::memory_order_acquire)) m_BlockCond.wait(lock); @@ -358,9 +349,7 @@ class asynchronous_sink : bool try_consume(record_view const& rec) BOOST_OVERRIDE { if (!m_FlushRequested.load(boost::memory_order_acquire)) - { return queue_base_type::try_enqueue(rec); - } else return false; } @@ -368,7 +357,7 @@ class asynchronous_sink : /*! * The method starts record feeding loop and effectively blocks until either of this happens: * - * \li the thread is interrupted due to either standard thread interruption or a call to \c stop + * \li the thread is interrupted due to a call to \c stop * \li an exception is thrown while processing a log record in the backend, and the exception is * not terminated by the exception handler, if one is installed * @@ -378,7 +367,7 @@ class asynchronous_sink : { // First check that no other thread is running { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (start_feeding_operation(lock, feeding_records)) return; } @@ -426,9 +415,9 @@ class asynchronous_sink : */ void stop() { - boost::thread feeding_thread; + std::thread feeding_thread; { - lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); m_StopRequested.store(true, boost::memory_order_release); queue_base_type::interrupt_dequeue(); @@ -449,7 +438,7 @@ class asynchronous_sink : { // First check that no other thread is running { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (start_feeding_operation(lock, feeding_records)) return; } @@ -468,7 +457,7 @@ class asynchronous_sink : void flush() BOOST_OVERRIDE { { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (static_cast< unsigned int >(m_ActiveOperation & feeding_records) != 0u) { // There is already a thread feeding records, let it do the job @@ -497,11 +486,11 @@ class asynchronous_sink : //! The method spawns record feeding thread void start_feeding_thread() { - boost::thread(run_func(this)).swap(m_DedicatedFeedingThread); + std::thread(run_func(this)).swap(m_DedicatedFeedingThread); } //! Starts record feeding operation. The method blocks or throws if another feeding operation is in progress. - bool start_feeding_operation(unique_lock< frontend_mutex_type >& lock, operation op) + bool start_feeding_operation(std::unique_lock< frontend_mutex_type >& lock, operation op) { while (m_ActiveOperation != idle) { @@ -527,7 +516,7 @@ class asynchronous_sink : { try { - lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); m_ActiveOperation = idle; m_StopRequested.store(false, boost::memory_order_relaxed); m_BlockCond.notify_all(); diff --git a/include/boost/log/sinks/basic_sink_frontend.hpp b/include/boost/log/sinks/basic_sink_frontend.hpp index c446985e2b..b6409e317b 100644 --- a/include/boost/log/sinks/basic_sink_frontend.hpp +++ b/include/boost/log/sinks/basic_sink_frontend.hpp @@ -28,7 +28,6 @@ #if !defined(BOOST_LOG_NO_THREADS) #include #include -#include #include #include #include @@ -131,12 +130,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : { return m_Filter(attrs); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { if (m_ExceptionHandler.empty()) @@ -166,12 +159,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.consume(rec); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) @@ -191,10 +178,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : if (!backend_mutex.try_lock()) return false; } - catch (thread_interrupted&) - { - throw; - } catch (...) { boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); @@ -231,12 +214,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) @@ -464,12 +441,6 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.consume(rec, context->m_FormattedRecord); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());) @@ -489,10 +460,6 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : if (!backend_mutex.try_lock()) return false; } - catch (thread_interrupted&) - { - throw; - } catch (...) { boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); diff --git a/include/boost/log/sinks/block_on_overflow.hpp b/include/boost/log/sinks/block_on_overflow.hpp index 5bfcda2bcd..d5b3d1ff8a 100644 --- a/include/boost/log/sinks/block_on_overflow.hpp +++ b/include/boost/log/sinks/block_on_overflow.hpp @@ -26,10 +26,10 @@ #error Boost.Log: This header content is only supported in multithreaded environment #endif +#include #include #include #include -#include #include #include @@ -58,7 +58,7 @@ class block_on_overflow struct thread_context : public thread_context_hook_t { - condition_variable cond; + std::condition_variable cond; bool result; thread_context() : result(true) {} diff --git a/include/boost/log/sinks/bounded_fifo_queue.hpp b/include/boost/log/sinks/bounded_fifo_queue.hpp index 9a82b3ad39..227191e6d1 100644 --- a/include/boost/log/sinks/bounded_fifo_queue.hpp +++ b/include/boost/log/sinks/bounded_fifo_queue.hpp @@ -28,9 +28,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -64,13 +63,13 @@ class bounded_fifo_queue : private: typedef OverflowStrategyT overflow_strategy; typedef std::queue< record_view > queue_type; - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; private: //! Synchronization primitive mutex_type m_mutex; //! Condition to block the consuming thread on - condition_variable m_cond; + std::condition_variable m_cond; //! Log record queue queue_type m_queue; //! Interruption flag @@ -90,7 +89,7 @@ class bounded_fifo_queue : //! Enqueues log record to the queue void enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); std::size_t size = m_queue.size(); for (; size >= MaxQueueSizeV; size = m_queue.size()) { @@ -106,7 +105,7 @@ class bounded_fifo_queue : //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { const std::size_t size = m_queue.size(); @@ -133,7 +132,7 @@ class bounded_fifo_queue : //! Attempts to dequeue log record from the queue, does not block if the queue is empty bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { @@ -149,7 +148,7 @@ class bounded_fifo_queue : //! Dequeues log record from the queue, blocks if the queue is empty bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { @@ -174,7 +173,7 @@ class bounded_fifo_queue : //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; overflow_strategy::interrupt(); m_cond.notify_one(); diff --git a/include/boost/log/sinks/bounded_ordering_queue.hpp b/include/boost/log/sinks/bounded_ordering_queue.hpp index 157843f9ab..a457b4b3fd 100644 --- a/include/boost/log/sinks/bounded_ordering_queue.hpp +++ b/include/boost/log/sinks/bounded_ordering_queue.hpp @@ -29,13 +29,9 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -73,7 +69,7 @@ class bounded_ordering_queue : { private: typedef OverflowStrategyT overflow_strategy; - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; typedef sinks::aux::enqueued_record enqueued_record; typedef std::priority_queue< @@ -83,12 +79,12 @@ class bounded_ordering_queue : > queue_type; private: - //! Ordering window duration, in milliseconds - const uint64_t m_ordering_window; + //! Ordering window duration + const std::chrono::steady_clock::duration m_ordering_window; //! Synchronization primitive mutex_type m_mutex; //! Condition to block the consuming thread on - condition_variable m_cond; + std::condition_variable m_cond; //! Log record queue queue_type m_queue; //! Interruption flag @@ -98,16 +94,16 @@ class bounded_ordering_queue : /*! * Returns ordering window size specified during initialization */ - posix_time::time_duration get_ordering_window() const + std::chrono::steady_clock::duration get_ordering_window() const { - return posix_time::milliseconds(m_ordering_window); + return m_ordering_window; } /*! * Returns default ordering window size. * The default window size is specific to the operating system thread scheduling mechanism. */ - static posix_time::time_duration get_default_ordering_window() + static BOOST_CONSTEXPR std::chrono::steady_clock::duration get_default_ordering_window() BOOST_NOEXCEPT { // The main idea behind this parameter is that the ordering window should be large enough // to allow the frontend to order records from different threads on an attribute @@ -116,14 +112,14 @@ class bounded_ordering_queue : // For instance, on Windows it defaults to around 15-16 ms. // * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to // switch threads on any known OS. It can be tuned for other platforms as needed. - return posix_time::milliseconds(30); + return std::chrono::milliseconds(30); } protected: //! Initializing constructor template< typename ArgsT > explicit bounded_ordering_queue(ArgsT const& args) : - m_ordering_window(args[keywords::ordering_window || &bounded_ordering_queue::get_default_ordering_window].total_milliseconds()), + m_ordering_window(std::chrono::duration_cast< std::chrono::steady_clock::duration >(args[keywords::ordering_window || &bounded_ordering_queue::get_default_ordering_window])), m_queue(args[keywords::order]), m_interruption_requested(false) { @@ -132,7 +128,7 @@ class bounded_ordering_queue : //! Enqueues log record to the queue void enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); std::size_t size = m_queue.size(); for (; size >= MaxQueueSizeV; size = m_queue.size()) { @@ -148,7 +144,7 @@ class bounded_ordering_queue : //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { const std::size_t size = m_queue.size(); @@ -169,13 +165,13 @@ class bounded_ordering_queue : //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty bool try_dequeue_ready(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window) + if ((now - elem.m_timestamp) >= m_ordering_window) { // We got a new element rec = elem.m_record; @@ -191,7 +187,7 @@ class bounded_ordering_queue : //! Attempts to dequeue log record from the queue, does not block if the queue is empty bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { @@ -208,16 +204,16 @@ class bounded_ordering_queue : //! Dequeues log record from the queue, blocks if the queue is empty bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { const std::size_t size = m_queue.size(); if (size > 0) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - const uint64_t difference = (now - elem.m_timestamp).milliseconds(); + const auto difference = now - elem.m_timestamp; if (difference >= m_ordering_window) { rec = elem.m_record; @@ -228,7 +224,7 @@ class bounded_ordering_queue : else { // Wait until the element becomes ready to be processed - m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference)); + m_cond.wait_for(lock, m_ordering_window - difference); } } else @@ -244,7 +240,7 @@ class bounded_ordering_queue : //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; overflow_strategy::interrupt(); m_cond.notify_one(); diff --git a/include/boost/log/sinks/sync_frontend.hpp b/include/boost/log/sinks/sync_frontend.hpp index 738b688055..a498cad14a 100644 --- a/include/boost/log/sinks/sync_frontend.hpp +++ b/include/boost/log/sinks/sync_frontend.hpp @@ -15,6 +15,7 @@ #ifndef BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_ +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -75,7 +75,7 @@ class synchronous_sink : private: //! Synchronization mutex type - typedef boost::recursive_mutex backend_mutex_type; + typedef std::recursive_mutex backend_mutex_type; public: //! Sink implementation type diff --git a/include/boost/log/sinks/unbounded_ordering_queue.hpp b/include/boost/log/sinks/unbounded_ordering_queue.hpp index c84d8fd4d8..df335f3220 100644 --- a/include/boost/log/sinks/unbounded_ordering_queue.hpp +++ b/include/boost/log/sinks/unbounded_ordering_queue.hpp @@ -28,13 +28,9 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -69,7 +65,7 @@ template< typename OrderT > class unbounded_ordering_queue { private: - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; typedef sinks::aux::enqueued_record enqueued_record; typedef std::priority_queue< @@ -79,12 +75,12 @@ class unbounded_ordering_queue > queue_type; private: - //! Ordering window duration, in milliseconds - const uint64_t m_ordering_window; + //! Ordering window duration + const std::chrono::steady_clock::duration m_ordering_window; //! Synchronization mutex mutex_type m_mutex; //! Condition for blocking - condition_variable m_cond; + std::condition_variable m_cond; //! Thread-safe queue queue_type m_queue; //! Interruption flag @@ -94,16 +90,16 @@ class unbounded_ordering_queue /*! * Returns ordering window size specified during initialization */ - posix_time::time_duration get_ordering_window() const + std::chrono::steady_clock::duration get_ordering_window() const { - return posix_time::milliseconds(m_ordering_window); + return m_ordering_window; } /*! * Returns default ordering window size. * The default window size is specific to the operating system thread scheduling mechanism. */ - static posix_time::time_duration get_default_ordering_window() + static BOOST_CONSTEXPR std::chrono::steady_clock::duration get_default_ordering_window() BOOST_NOEXCEPT { // The main idea behind this parameter is that the ordering window should be large enough // to allow the frontend to order records from different threads on an attribute @@ -112,14 +108,14 @@ class unbounded_ordering_queue // For instance, on Windows it defaults to around 15-16 ms. // * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to // switch threads on any known OS. It can be tuned for other platforms as needed. - return posix_time::milliseconds(30); + return std::chrono::milliseconds(30); } protected: //! Initializing constructor template< typename ArgsT > explicit unbounded_ordering_queue(ArgsT const& args) : - m_ordering_window(args[keywords::ordering_window || &unbounded_ordering_queue::get_default_ordering_window].total_milliseconds()), + m_ordering_window(std::chrono::duration_cast< std::chrono::steady_clock::duration >(args[keywords::ordering_window || &unbounded_ordering_queue::get_default_ordering_window])), m_queue(args[keywords::order]), m_interruption_requested(false) { @@ -128,14 +124,14 @@ class unbounded_ordering_queue //! Enqueues log record to the queue void enqueue(record_view const& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); enqueue_unlocked(rec); } //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { enqueue_unlocked(rec); @@ -148,12 +144,12 @@ class unbounded_ordering_queue //! Attempts to dequeue a log record ready for processing from the queue, does not block if no log records are ready to be processed bool try_dequeue_ready(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window) + if ((now - elem.m_timestamp) >= m_ordering_window) { // We got a new element rec = elem.m_record; @@ -168,7 +164,7 @@ class unbounded_ordering_queue //! Attempts to dequeue log record from the queue, does not block. bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { enqueued_record const& elem = m_queue.top(); @@ -183,14 +179,14 @@ class unbounded_ordering_queue //! Dequeues log record from the queue, blocks if no log records are ready to be processed bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { if (!m_queue.empty()) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - const uint64_t difference = (now - elem.m_timestamp).milliseconds(); + const auto difference = now - elem.m_timestamp; if (difference >= m_ordering_window) { // We got a new element @@ -201,7 +197,7 @@ class unbounded_ordering_queue else { // Wait until the element becomes ready to be processed - m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference)); + m_cond.wait_for(lock, m_ordering_window - difference); } } else @@ -218,7 +214,7 @@ class unbounded_ordering_queue //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; m_cond.notify_one(); } diff --git a/include/boost/log/sources/exception_handler_feature.hpp b/include/boost/log/sources/exception_handler_feature.hpp index feedc247d8..b2b1acde56 100644 --- a/include/boost/log/sources/exception_handler_feature.hpp +++ b/include/boost/log/sources/exception_handler_feature.hpp @@ -26,9 +26,6 @@ #include #include #include -#if !defined(BOOST_LOG_NO_THREADS) -#include -#endif #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -155,12 +152,6 @@ class basic_exception_handler_logger : { return base_type::open_record_unlocked(args); } -#ifndef BOOST_LOG_NO_THREADS - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { handle_exception(); @@ -177,12 +168,6 @@ class basic_exception_handler_logger : { base_type::push_record_unlocked(boost::move(rec)); } -#ifndef BOOST_LOG_NO_THREADS - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { handle_exception(); diff --git a/include/boost/log/utility/strictest_lock.hpp b/include/boost/log/utility/strictest_lock.hpp index e40e400f6e..2b5ac9fa0c 100644 --- a/include/boost/log/utility/strictest_lock.hpp +++ b/include/boost/log/utility/strictest_lock.hpp @@ -73,6 +73,37 @@ struct thread_access_mode_of< no_lock< MutexT > > : boost::integral_constant< lo #if !defined(BOOST_LOG_NO_THREADS) +#if !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename MutexT > +struct thread_access_mode_of< std::lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#else // !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename... MutexesT > +struct thread_access_mode_of< std::lock_guard< MutexesT... > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#endif // !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) + +template< typename MutexT > +struct thread_access_mode_of< std::unique_lock< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; + +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) +template< typename MutexT > +struct thread_access_mode_of< std::shared_lock< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > +{ +}; +#endif // !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) + +#if defined(__cpp_lib_scoped_lock) && (__cpp_lib_scoped_lock >= 201703l) +template< typename... MutexesT > +struct thread_access_mode_of< std::scoped_lock< MutexesT... > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#endif + template< typename MutexT > struct thread_access_mode_of< lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > { diff --git a/src/core.cpp b/src/core.cpp index 657de0eb8d..1da9d30728 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -250,7 +249,8 @@ struct core::implementation : //! Creates a seed for RNG static uint32_t get_random_seed() { - uint32_t seed = static_cast< uint32_t >(posix_time::microsec_clock::universal_time().time_of_day().ticks()); + uint64_t now = static_cast< uint64_t >(std::chrono::system_clock::now().time_since_epoch().count()); + uint32_t seed = static_cast< uint32_t >(now) ^ static_cast< uint32_t >(now >> 32u); #if !defined(BOOST_LOG_NO_THREADS) seed += static_cast< uint32_t >(log::aux::this_thread::get_id().native_id()); #endif @@ -369,14 +369,6 @@ struct core::implementation : } } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - if (rec_impl) - rec_impl->destroy(); - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (rec_impl) @@ -463,12 +455,6 @@ struct core::implementation : impl->push_back_accepting_sink(sink); } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_exception_handler.empty()) @@ -644,12 +630,6 @@ BOOST_LOG_API void core::flush() { it->get()->flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_impl->m_exception_handler.empty()) @@ -664,12 +644,6 @@ BOOST_LOG_API void core::flush() { m_impl->m_default_sink->flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_impl->m_exception_handler.empty()) @@ -762,12 +736,6 @@ BOOST_LOG_API void core::push_record_move(record& rec) else break; } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { // Lock the core to be safe against any attribute or sink set modifications @@ -782,12 +750,6 @@ BOOST_LOG_API void core::push_record_move(record& rec) end->swap(*it); } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { // Lock the core to be safe against any attribute or sink set modifications diff --git a/src/default_sink.cpp b/src/default_sink.cpp index 00188f35fb..72d0aa2173 100644 --- a/src/default_sink.cpp +++ b/src/default_sink.cpp @@ -17,7 +17,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include +#include #include #endif #include @@ -207,14 +207,14 @@ bool default_sink::will_consume(attribute_value_set const&) void default_sink::consume(record_view const& rec) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_mutex);) m_message_visitor(m_message_name, rec.attribute_values(), message_printer(m_severity_extractor(m_severity_name, rec).get())); std::fflush(stdout); } void default_sink::flush() { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_mutex);) std::fflush(stdout); } diff --git a/src/default_sink.hpp b/src/default_sink.hpp index ed2c033886..a89b862aaa 100644 --- a/src/default_sink.hpp +++ b/src/default_sink.hpp @@ -25,7 +25,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include +#include #endif #include @@ -47,7 +47,7 @@ class default_sink : { private: #if !defined(BOOST_LOG_NO_THREADS) - typedef mutex mutex_type; + typedef std::mutex mutex_type; mutex_type m_mutex; #endif attribute_name const m_severity_name, m_message_name; diff --git a/src/event.cpp b/src/event.cpp index bbc033e7a2..16f3f451bb 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -45,7 +45,7 @@ #else -#include +#include #endif @@ -222,7 +222,7 @@ BOOST_LOG_API generic_event::~generic_event() //! Waits for the object to become signalled BOOST_LOG_API void generic_event::wait() { - boost::unique_lock< boost::mutex > lock(m_mutex); + std::unique_lock< std::mutex > lock(m_mutex); while (!m_state) { m_cond.wait(lock); @@ -233,7 +233,7 @@ BOOST_LOG_API void generic_event::wait() //! Sets the object to a signalled state BOOST_LOG_API void generic_event::set_signalled() { - boost::lock_guard< boost::mutex > lock(m_mutex); + std::lock_guard< std::mutex > lock(m_mutex); if (!m_state) { m_state = true; diff --git a/src/global_logger_storage.cpp b/src/global_logger_storage.cpp index 6662f19f34..abb5bc346f 100644 --- a/src/global_logger_storage.cpp +++ b/src/global_logger_storage.cpp @@ -23,8 +23,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include @@ -47,7 +46,7 @@ struct loggers_repository : #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization primitive - mutable mutex m_Mutex; + mutable std::mutex m_Mutex; #endif //! Map of logger holders loggers_map_t m_Loggers; @@ -61,7 +60,7 @@ BOOST_LOG_API shared_ptr< logger_holder_base > global_storage::get_or_init(typei typedef loggers_repository::loggers_map_t loggers_map_t; loggers_repository& repo = loggers_repository::get(); - BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex > lock(repo.m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(repo.m_Mutex);) loggers_map_t::iterator it = repo.m_Loggers.find(key); if (it != repo.m_Loggers.end()) { diff --git a/src/once_block.cpp b/src/once_block.cpp index c76009da0a..67326d02b0 100644 --- a/src/once_block.cpp +++ b/src/once_block.cpp @@ -108,12 +108,11 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 #include // atexit +#include +#include #include #include #include -#include -#include -#include #include namespace boost { @@ -229,13 +228,13 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { public once_block_impl_base { private: - mutex m_Mutex; - condition_variable m_Cond; + std::mutex m_Mutex; + std::condition_variable m_Cond; public: bool enter_once_block(once_block_flag volatile& flag) { - unique_lock< mutex > lock(m_Mutex); + std::unique_lock< std::mutex > lock(m_Mutex); while (flag.status != once_block_flag::initialized) { @@ -261,7 +260,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { void commit(once_block_flag& flag) { { - lock_guard< mutex > lock(m_Mutex); + std::lock_guard< std::mutex > lock(m_Mutex); flag.status = once_block_flag::initialized; } m_Cond.notify_all(); @@ -270,7 +269,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { void rollback(once_block_flag& flag) { { - lock_guard< mutex > lock(m_Mutex); + std::lock_guard< std::mutex > lock(m_Mutex); flag.status = once_block_flag::uninitialized; } m_Cond.notify_all(); diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 978a6a2052..de639df08a 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -866,7 +866,7 @@ template< typename CharT > BOOST_LOG_SETUP_API void register_sink_factory(const char* sink_name, shared_ptr< sink_factory< CharT > > const& factory) { sinks_repository< CharT >& repo = sinks_repository< CharT >::get(); - BOOST_LOG_EXPR_IF_MT(lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);) + BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);) repo.m_Factories[sink_name] = factory; } diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index e505893053..15a47e3929 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -43,8 +43,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include "unique_ptr.hpp" @@ -125,14 +124,14 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Syslog service initializer (implemented as a weak singleton) #if !defined(BOOST_LOG_NO_THREADS) class native_syslog_initializer : - private log::aux::lazy_singleton< native_syslog_initializer, mutex > + private log::aux::lazy_singleton< native_syslog_initializer, std::mutex > #else class native_syslog_initializer #endif { #if !defined(BOOST_LOG_NO_THREADS) - friend class log::aux::lazy_singleton< native_syslog_initializer, mutex >; - typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder; + friend class log::aux::lazy_singleton< native_syslog_initializer, std::mutex >; + typedef log::aux::lazy_singleton< native_syslog_initializer, std::mutex > mutex_holder; #endif private: @@ -163,7 +162,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { static shared_ptr< native_syslog_initializer > get_instance(std::string const& ident, int facility) { #if !defined(BOOST_LOG_NO_THREADS) - lock_guard< mutex > lock(mutex_holder::get()); + std::lock_guard< std::mutex > lock(mutex_holder::get()); #endif static weak_ptr< native_syslog_initializer > instance; shared_ptr< native_syslog_initializer > p(instance.lock()); @@ -354,7 +353,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { #if !defined(BOOST_LOG_NO_THREADS) //! A synchronization primitive to protect the host name resolver - mutex m_Mutex; + std::mutex m_Mutex; //! The resolver is used to acquire connection endpoints asio::ip::udp::resolver m_HostNameResolver; #endif // !defined(BOOST_LOG_NO_THREADS) @@ -539,7 +538,7 @@ BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, un asio::ip::udp::endpoint local_address; { - lock_guard< mutex > lock(impl->m_pService->m_Mutex); + std::lock_guard< std::mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( impl->m_Protocol, @@ -585,7 +584,7 @@ BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, u asio::ip::udp::endpoint remote_address; { - lock_guard< mutex > lock(impl->m_pService->m_Mutex); + std::lock_guard< std::mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( impl->m_Protocol, diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index a147518ed0..6c2e8633b2 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -58,8 +58,7 @@ #include "unique_ptr.hpp" #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif // !defined(BOOST_LOG_NO_THREADS) #include @@ -674,7 +673,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex - mutex m_Mutex; + std::mutex m_Mutex; #endif // !defined(BOOST_LOG_NO_THREADS) //! Total file size upper limit @@ -765,7 +764,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { private: #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex - mutex m_Mutex; + std::mutex m_Mutex; #endif // !defined(BOOST_LOG_NO_THREADS) //! The list of file collectors file_collectors m_Collectors; @@ -864,7 +863,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::create_directories(m_StorageDir); } - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_list::iterator it = m_Files.begin(); const file_list::iterator end = m_Files.end(); @@ -982,7 +981,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::file_status status = filesystem::status(dir, ec); if (status.type() == filesystem::directory_file) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_list files; filesystem::directory_iterator it(dir), end; @@ -1031,7 +1030,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! The function updates storage restrictions void file_collector::update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) m_MaxSize = (std::min)(m_MaxSize, max_size); m_MinFreeSpace = (std::max)(m_MinFreeSpace, min_free_space); @@ -1043,7 +1042,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { shared_ptr< file::collector > file_collector_repository::get_collector( filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_collectors::iterator it = std::find_if(m_Collectors.begin(), m_Collectors.end(), [&target_dir](file_collector const& collector) { return collector.is_governed(target_dir); }); @@ -1071,7 +1070,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Removes the file collector from the list void file_collector_repository::remove_collector(file_collector* p) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) m_Collectors.erase(m_Collectors.iterator_to(*p)); } diff --git a/src/thread_id.cpp b/src/thread_id.cpp index e3a70a4626..c80d7ab69d 100644 --- a/src/thread_id.cpp +++ b/src/thread_id.cpp @@ -29,7 +29,7 @@ #include #include #elif defined(BOOST_WINDOWS) -#include +#include // at_thread_exit #include #else #include diff --git a/src/timer.cpp b/src/timer.cpp index db55ea7bcd..928900ccd2 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -22,8 +22,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include #include @@ -41,7 +40,7 @@ class BOOST_SYMBOL_VISIBLE timer::impl : private: #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex type - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; //! Synchronization mutex mutex_type m_Mutex; #endif @@ -70,7 +69,7 @@ class BOOST_SYMBOL_VISIBLE timer::impl : { uint64_t duration; { - BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_Mutex);) LARGE_INTEGER li; QueryPerformanceCounter(&li); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 34a8324fbb..a3bb840f1e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -55,7 +55,6 @@ project /boost/filesystem//boost_filesystem /boost/test//boost_unit_test_framework single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread : default-build # Testers typically don't specify threading environment and the library can be built and tested for single and multi. I'm more interested in multi though. multi diff --git a/test/common/test_barrier.hpp b/test/common/test_barrier.hpp new file mode 100644 index 0000000000..72b2a26f11 --- /dev/null +++ b/test/common/test_barrier.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2024 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ +#define BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ + +#include +#include + +//! A simplified version of thread barrier from Boost.Thread and C++20 std::barrier +class test_barrier +{ +private: + std::mutex m_mutex; + std::condition_variable m_cond; + unsigned int m_generation; + unsigned int m_count; + const unsigned int m_initial_count; + +public: + explicit test_barrier(unsigned int initial_count) : + m_generation(0u), m_count(initial_count), m_initial_count(initial_count) + { + } + + test_barrier(test_barrier const&) = delete; + test_barrier& operator= (test_barrier const&) = delete; + + void arrive_and_wait() + { + std::unique_lock< std::mutex > lock(m_mutex); + + --m_count; + if (m_count == 0u) + { + ++m_generation; + m_count = m_initial_count; + m_cond.notify_all(); + return; + } + + const unsigned int generation = m_generation; + do + { + m_cond.wait(lock); + } + while (m_generation == generation); + } + + void wake_all() + { + std::lock_guard< std::mutex > lock(m_mutex); + ++m_generation; + m_count = m_initial_count; + m_cond.notify_all(); + } +}; + +#endif // BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ diff --git a/test/performance/record_emission.cpp b/test/performance/record_emission.cpp index 0dd388cb05..92446cace8 100644 --- a/test/performance/record_emission.cpp +++ b/test/performance/record_emission.cpp @@ -17,16 +17,13 @@ // #define BOOST_LOG_DYN_LINK 1 #define BOOST_NO_DYN_LINK 1 +#include +#include +#include #include #include -#include -#include #include #include -#include -#include -#include -#include #include #include @@ -39,6 +36,8 @@ #include +#include "test_barrier.hpp" + enum config { RECORD_COUNT = 20000000, @@ -76,12 +75,12 @@ namespace { } // namespace -void test(unsigned int record_count, boost::barrier& bar) +void test(unsigned int record_count, test_barrier& bar) { BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); src::severity_logger< severity_level > slg; // src::logger lg; - bar.wait(); + bar.arrive_and_wait(); for (unsigned int i = 0; i < record_count; ++i) { @@ -93,7 +92,6 @@ void test(unsigned int record_count, boost::barrier& bar) int main(int argc, char* argv[]) { std::cout << "Test config: " << THREAD_COUNT << " threads, " << SINK_COUNT << " sinks, " << RECORD_COUNT << " records" << std::endl; -//__debugbreak(); // typedef sinks::unlocked_sink< fake_backend > fake_sink; // typedef sinks::synchronous_sink< fake_backend > fake_sink; typedef sinks::asynchronous_sink< fake_backend > fake_sink; @@ -110,19 +108,19 @@ int main(int argc, char* argv[]) // logging::core::get()->set_filter(severity > error); // all records don't pass the filter const unsigned int record_count = RECORD_COUNT / THREAD_COUNT; - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + test_barrier bar(THREAD_COUNT); + std::vector< std::thread > threads(THREAD_COUNT - 1); - for (unsigned int i = 1; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&test, record_count, boost::ref(bar))); + for (unsigned int i = 0; i < THREAD_COUNT - 1; ++i) + threads[i] = std::thread([&bar, record_count]() { test(record_count, bar); }); - boost::posix_time::ptime start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(), end; + const auto start = std::chrono::steady_clock::now(); test(record_count, bar); - if (THREAD_COUNT > 1) - threads.join_all(); - end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(); + for (unsigned int i = 0; i < THREAD_COUNT - 1; ++i) + threads[i].join(); + const auto finish = std::chrono::steady_clock::now(); - unsigned long long duration = (end - start).total_microseconds(); + unsigned long long duration_us = std::chrono::duration_cast< std::chrono::microseconds >(finish - start).count(); std::cout << "Test duration: " << duration << " us (" << std::fixed << std::setprecision(3) << static_cast< double >(RECORD_COUNT) / (static_cast< double >(duration) / 1000000.0) diff --git a/test/run/core.cpp b/test/run/core.cpp index 69b42647a2..99ff64e743 100644 --- a/test/run/core.cpp +++ b/test/run/core.cpp @@ -28,7 +28,7 @@ #include #include #ifndef BOOST_LOG_NO_THREADS -#include +#include #endif // BOOST_LOG_NO_THREADS #include "char_definitions.hpp" #include "test_sink.hpp" @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(attributes) } #ifndef BOOST_LOG_NO_THREADS { - boost::thread th(&thread_attributes_test); + std::thread th(&thread_attributes_test); th.join(); BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL); BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL); diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index aae22f2a0b..62732590a3 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -39,11 +39,10 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) +#include +#include #include -#include #include -#include -#include #endif #include "char_definitions.hpp" @@ -351,9 +350,9 @@ BOOST_AUTO_TEST_CASE(multithreaded_message_passing) unsigned int failure_count1 = 0, failure_count2 = 0, failure_count3 = 0; boost::atomic_thread_fence(boost::memory_order_release); - boost::thread thread1(&multithreaded_message_passing_feeding_thread, "Thread 1", boost::ref(failure_count1)); - boost::thread thread2(&multithreaded_message_passing_feeding_thread, "Thread 2", boost::ref(failure_count2)); - boost::thread thread3(&multithreaded_message_passing_feeding_thread, "Thread 3", boost::ref(failure_count3)); + std::thread thread1([&failure_count1]() { multithreaded_message_passing_feeding_thread("Thread 1", failure_count1); }); + std::thread thread2([&failure_count2]() { multithreaded_message_passing_feeding_thread("Thread 2", failure_count2); }); + std::thread thread3([&failure_count3]() { multithreaded_message_passing_feeding_thread("Thread 3", failure_count3); }); BOOST_TEST_PASSPOINT(); @@ -447,14 +446,14 @@ BOOST_AUTO_TEST_CASE(stop_reset_local) BOOST_TEST_PASSPOINT(); // Case 1: Let the feeder block and then we unblock it with stop_local() - boost::thread feeder_thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 3); - boost::thread reader_thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 1); + std::thread feeder_thread([&feeder_queue, &feeder_results]() { stop_reset_feeding_thread(feeder_queue, feeder_results, 3); }); + std::thread reader_thread([&reader_queue, &reader_results]() { stop_reset_reading_thread(reader_queue, reader_results, 1); }); BOOST_TEST_PASSPOINT(); reader_thread.join(); BOOST_TEST_PASSPOINT(); - boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); BOOST_TEST_PASSPOINT(); @@ -480,14 +479,14 @@ BOOST_AUTO_TEST_CASE(stop_reset_local) BOOST_TEST_PASSPOINT(); // Case 2: Let the reader block and then we unblock it with stop_local() - boost::thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 1).swap(feeder_thread); - boost::thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 2).swap(reader_thread); + feeder_thread = std::thread([&feeder_queue, &feeder_results]() { stop_reset_feeding_thread(feeder_queue, feeder_results, 1); }); + reader_thread = std::thread([&reader_queue, &reader_results]() { stop_reset_reading_thread(reader_queue, reader_results, 2); }); BOOST_TEST_PASSPOINT(); feeder_thread.join(); BOOST_TEST_PASSPOINT(); - boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); BOOST_TEST_PASSPOINT(); diff --git a/test/run/util_once_block.cpp b/test/run/util_once_block.cpp index 4149c74284..ced2e94f44 100644 --- a/test/run/util_once_block.cpp +++ b/test/run/util_once_block.cpp @@ -21,12 +21,9 @@ #if !defined(BOOST_LOG_NO_THREADS) -#include -#include -#include -#include -#include -#include +#include +#include +#include "test_barrier.hpp" namespace logging = boost::log; @@ -36,8 +33,8 @@ enum config LOOP_COUNT = 100 }; -boost::mutex m; -typedef boost::lock_guard< boost::mutex > scoped_lock; +std::mutex m; +typedef std::lock_guard< std::mutex > scoped_lock; logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT; int var_to_init_once_flag = 0; @@ -50,10 +47,10 @@ void initialize_variable() } -void once_block_flag_thread(boost::barrier& barrier) +void once_block_flag_thread(test_barrier& barrier) { int my_once_value = 0; - barrier.wait(); + barrier.arrive_and_wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK_FLAG(flag) @@ -74,21 +71,25 @@ void once_block_flag_thread(boost::barrier& barrier) // The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works BOOST_AUTO_TEST_CASE(once_block_flag) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_flag_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_flag_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; } @@ -97,10 +98,10 @@ BOOST_AUTO_TEST_CASE(once_block_flag) int var_to_init_once = 0; -void once_block_thread(boost::barrier& barrier) +void once_block_thread(test_barrier& barrier) { int my_once_value = 0; - barrier.wait(); + barrier.arrive_and_wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK() @@ -123,21 +124,25 @@ void once_block_thread(boost::barrier& barrier) // The test checks if the BOOST_LOG_ONCE_BLOCK macro works BOOST_AUTO_TEST_CASE(once_block) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } - catch(...) + catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; } @@ -152,9 +157,9 @@ struct my_exception unsigned int pass_counter = 0; unsigned int exception_counter = 0; -void once_block_with_exception_thread(boost::barrier& barrier) +void once_block_with_exception_thread(test_barrier& barrier) { - barrier.wait(); + barrier.arrive_and_wait(); try { BOOST_LOG_ONCE_BLOCK() @@ -177,21 +182,25 @@ void once_block_with_exception_thread(boost::barrier& barrier) // The test verifies that the once_block flag is not set if an exception is thrown from the once-block BOOST_AUTO_TEST_CASE(once_block_retried_on_exception) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_with_exception_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_with_exception_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } - catch(...) + catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; }