3977{
3978#ifdef __cpp_exceptions
3979 try
3980 {
3981#endif
3982
3983 no_color = (std::getenv("NO_COLOR") != nullptr);
3984
3985
3986 std::map<std::string, bool> defaults;
3987 std::ifstream default_args_file("default_args.txt");
3988 if (!default_args_file.is_open())
3989 default_args_file.open("../default_args.txt");
3990 if (default_args_file.is_open())
3991 {
3993 std::getline(default_args_file, line);
3994 std::istringstream iss(line);
3995 std::string arg;
3996 while (iss >> arg)
3997 defaults[arg] = true;
3998 default_args_file.close();
3999 }
4000 else
4001 {
4002 defaults = {{"help", false}, {"stdout", true}, {"log", true}, {"tests", true}, {"deadlock", false}, {"benchmarks", true}, {"plot", false}, {"save", false}};
4003 }
4004
4005
4006 arg_parser args(argc, argv);
4007 args.add_argument("help", "Show this help message and exit.", defaults["help"]);
4008 args.add_argument("stdout", "Print to the standard output.", defaults["stdout"]);
4009 args.add_argument("log", "Print to a log file.", defaults["log"]);
4010 args.add_argument("tests", "Perform standard tests.", defaults["tests"]);
4011 args.add_argument("deadlock", "Perform long deadlock tests.", defaults["deadlock"]);
4012 args.add_argument("benchmarks", "Perform full Mandelbrot plot benchmarks.", defaults["benchmarks"]);
4013 args.add_argument("plot", "Perform quick Mandelbrot plot benchmarks.", defaults["plot"]);
4014 args.add_argument("save", "Save the Mandelbrot plot to a file.", defaults["save"]);
4015
4016 if (args.size() > 0)
4017 {
4018 if (args["help"] || !args.verify())
4019 {
4020 show_intro();
4021 args.show_help();
4022 return 0;
4023 }
4024 if (!args["stdout"] && !args["log"])
4025 {
4026 show_intro();
4027 args.show_help();
4028 logln_ansi(ansi_error, "\nERROR: No output stream specified! Please enter one or more of: log, stdout. Aborting.");
4029 return 0;
4030 }
4031 if (!args["benchmarks"] && !args["deadlock"] && !args["plot"] && !args["tests"])
4032 {
4033 show_intro();
4034 args.show_help();
4035 logln_ansi(ansi_error, "\nERROR: No tests or benchmarks requested! Please enter one or more of: benchmarks, deadlock, plot, tests. Aborting.");
4036 return 0;
4037 }
4038 }
4039
4040
4041 std::ofstream log_file;
4042
4043 sync_log.remove_stream(std::cout);
4044 if (args["log"])
4045 {
4046
4047 const std::string_view executable = args.get_executable();
4048 const std::size_t last_slash = executable.find_last_of("/\\") + 1;
4049 std::string exe_file(executable.substr(last_slash, executable.find('.', last_slash) - last_slash));
4050 if (exe_file.empty())
4051 exe_file = "BS_thread_pool_test";
4052
4053 const std::string log_filename = exe_file + "-" + get_time() + ".log";
4054 log_file.open(log_filename);
4055 if (log_file.is_open())
4056 {
4057 logln_ansi(ansi_info, "Generating log file: ", log_filename);
4058 sync_log.add_stream(log_file);
4059 }
4060 else
4061 {
4062 logln_ansi(ansi_error, "ERROR: Could not create a log file.");
4063 return 1;
4064 }
4065 }
4066
4067 use_stdout = args["stdout"];
4068 use_log = args["log"];
4069
4070 show_intro();
4071
4072 if (args["tests"])
4073 {
4074 print_header("Checking the constructor:");
4075 check_constructor();
4076
4077 print_header("Checking reset():");
4078 check_reset();
4079
4080 print_header("Checking detach_task() and submit_task():");
4081 check_task("detach_task()");
4082 check_task("submit_task()");
4083
4084 print_header("Checking submission of member functions as tasks:");
4085 check_member_function();
4086 check_member_function_within_object();
4087
4088 print_header("Checking submission of different callable types:");
4089 check_callables();
4090
4091 print_header("Checking wait(), wait_for(), and wait_until():");
4092 check_wait();
4093 check_wait_blocks();
4094 check_wait_for();
4095 check_wait_until();
4096 check_wait_multiple_deadlock();
4097#ifdef __cpp_exceptions
4098 check_wait_self_deadlock();
4099
4100 print_header("Checking exception handling:");
4101 check_exceptions_submit();
4102 check_exceptions_multi_future();
4103#else
4104 logln_ansi(ansi_info, "NOTE: Exceptions are disabled, skipping wait deadlock check and exception handling tests.");
4105#endif
4106
4107 print_header("Checking detach_loop() and submit_loop():");
4108 check_loop();
4109
4110 print_header("Checking detach_blocks() and submit_blocks():");
4111 check_blocks();
4112
4113 print_header("Checking detach_sequence() and submit_sequence():");
4114 check_sequence();
4115
4116 print_header("Checking task monitoring:");
4117 check_task_monitoring();
4118
4119 print_header("Checking pausing:");
4120 check_pausing();
4121
4122 print_header("Checking purge():");
4123 check_purge();
4124
4125 print_header("Checking parallelized vector operations:");
4126 check_vectors();
4127
4128 print_header("Checking task priority:");
4129 check_priority();
4130
4131 print_header("Checking thread initialization/cleanup functions and BS::this_thread:");
4132 check_init();
4133 check_cleanup();
4134 check_get_pool();
4135
4136 print_header("Checking that parallelized tasks do not get copied:");
4137 check_copy_all();
4138
4139 print_header("Checking that shared pointers are correctly shared:");
4140 check_shared_ptr_all();
4141
4142 print_header("Checking that tasks are destructed immediately after running:");
4143 check_task_destruct();
4144
4145 print_header("Checking BS::common_index_type:");
4146 check_common_index_type();
4147
4148#ifdef BS_THREAD_POOL_NATIVE_EXTENSIONS
4149 print_header("Checking native extensions:");
4150 #ifndef _WIN32
4151 if ((args["benchmarks"] || args["plot"]) && !BS::set_os_process_priority(BS::os_process_priority::realtime))
4152 {
4153 logln_ansi(ansi_info, "NOTE: Skipping process/thread priority checks since the test is running on Linux/macOS without root privileges and benchmarks are enabled. On Linux/macOS, if priorities are decreased, they cannot be increased back to normal without root privileges, so the process will be stuck on the lowest priority, and the benchmarks will be unreliable.\n");
4154 }
4155 else
4156 #endif
4157 {
4158
4159 check_os_thread_priorities();
4160 logln();
4161 check_os_process_priorities();
4162 logln();
4163 }
4164 check_os_thread_names();
4165 logln();
4166 #if defined(_WIN32) || defined(__linux__)
4167 check_os_thread_affinity();
4168 logln();
4169 check_os_process_affinity();
4170 #else
4171 logln_ansi(ansi_info, "NOTE: macOS does not support affinity, skipping the corresponding test.");
4172 #endif
4173#else
4174 logln_ansi(ansi_info, "NOTE: Native extensions disabled, skipping the corresponding test.");
4175#endif
4176 }
4177
4178 if (args["deadlock"])
4179 {
4180 print_header("Checking for deadlocks:");
4181 logln("Checking for destruction deadlocks...");
4182 check_deadlock(
4183 []
4184 {
4187 });
4188 logln("Checking for reset deadlocks...");
4190 check_deadlock(
4191 [&temp_pool]
4192 {
4194 });
4195 }
4196
4197 if (test_results::tests_failed > 0)
4198 {
4199 print_header("FAILURE: Passed " + std::to_string(test_results::tests_succeeded) + " checks, but failed " + std::to_string(test_results::tests_failed) + "!", '+', ansi_error);
4200 logln_ansi(ansi_error, "\nPlease submit a bug report at https://github.com/bshoshany/thread-pool/issues including the exact specifications of your system (OS, CPU, compiler, etc.) and the generated log file.");
4201 log_file.close();
4202 return static_cast<int>(test_results::tests_failed);
4203 }
4204
4205 if (test_results::tests_succeeded > 0)
4206 print_header("SUCCESS: Passed all " + std::to_string(test_results::tests_succeeded) + " checks!", '+', ansi_success);
4207
4208 if (args["benchmarks"] || args["plot"])
4209 check_performance(args["benchmarks"], args["plot"], args["save"]);
4210
4211 log_file.close();
4212 return 0;
4213#ifdef __cpp_exceptions
4214 }
4215 catch (const std::exception& e)
4216 {
4217 logln_ansi(ansi_error, "ERROR: Tests failed due to exception: ", e.what());
4218 return 1;
4219 }
4220#endif
4221}
A fast, lightweight, modern, and easy-to-use C++17/C++20/C++23 thread pool class.
Definition BS_thread_pool.hpp:1429
void detach_task(F &&task, const priority_t priority=0)
Submit a function with no arguments and no return value into the task queue, with the specified prior...
Definition BS_thread_pool.hpp:1627
void reset()
Reset the pool with the default number of threads (as if constructed with the default constructor)....
Definition BS_thread_pool.hpp:1744
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)