140#if defined(DEBUG) || defined(_DEBUG)
141 std::cerr << std::format(
142 "Shutting down periodic worker [{}] with outstanding callbacks [{}] and total invoke count [{}]\n",
144 outstandingCallback.load(std::memory_order_acquire),
145 invokeCounter.load(std::memory_order_acquire));
151 invokePeriod.store(std::chrono::microseconds(0), std::memory_order_release);
155#if defined(DEBUG) || defined(_DEBUG)
156 std::cerr << std::format(
"Signaled shutdown for periodic worker [{}], waiting for thread to join...\n", threadName);
162 processor.request_stop();
163 std::this_thread::sleep_for(std::chrono::milliseconds(100));
166 catch (
const std::exception& ex) {
167 std::cerr << std::format(
"Exception while shutting down periodic worker [{}]: {}", threadName, ex.what());
170#if defined(DEBUG) || defined(_DEBUG)
171 std::cerr << std::format(
"End of destructor for periodic worker [{}], waiting for thread to join...\n", threadName);
196 std::call_once(flag_forceCleanupTerminate, [&]() {
199 processor.request_stop();
200 std::this_thread::sleep_for(std::chrono::milliseconds(100));
201#if defined(_Linux_) || defined(__linux__) || defined(__linux) || (defined(__APPLE__) && defined(__MACH__))
202 auto nativeHandle = processor.native_handle();
203 std::cerr << std::format(
204 "forceCleanupTerminate - WARNING!! Calling native thread shutdown; only perform this when app is "
205 "ending! from: {}:{}",
208 pthread_cancel(nativeHandle);
210#elif defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64)
211 auto nativeHandle = processor.native_handle();
212 std::cerr << std::format(
213 "forceCleanupTerminate - WARNING!! Calling native thread shutdown; only perform this when app is "
214 "ending! from: {}:{}",
217 TerminateThread(nativeHandle, 0);
221 catch (
const std::exception& ex) {
222 std::cerr << std::format(
"forceCleanupTerminate - Exception while shutting down worker: {}", ex.what());
245 std::chrono::microseconds interval,
246 std::string name = {
"anonymous-periodic-worker"})
247 : callback(std::move(c))
248 , invokePeriod(interval)
249 , threadName(std::move(name))
254#if defined(NLOHMANN_JSON_VERSION_MAJOR)
273 nlohmann::json toJson()
const
277 return {{
"_typver"s,
"siddiqsoft.asynchrony-lib.periodic_worker/0.10"s},
278 {
"threadName", threadName},
279 {
"outstandingCallbacks", outstandingCallback.load(std::memory_order_acquire)},
280 {
"invokeCounter"s, invokeCounter.load(std::memory_order_acquire)},
281 {
"threadPriority"s, Pri},
282 {
"waitInterval"s, invokePeriod.load(std::memory_order_acquire).count()}};
288 std::once_flag flag_forceCleanupTerminate {};
292 std::atomic_uint outstandingCallback {0};
295 std::string threadName {
"anonymous-periodic-worker"};
298 std::atomic_uint64_t invokeCounter {0};
302 std::counting_semaphore<1> signal {0};
311 std::atomic<std::chrono::microseconds> invokePeriod {std::chrono::milliseconds(1500)};
314 std::function<void()> callback;
334 std::jthread processor {[&](std::stop_token st) {
335#if defined(WIN64) || defined(_WIN64) || defined(WIN32) || defined(_WIN32)
337 if constexpr (Pri != 0) SetThreadPriority(GetCurrentThread(), Pri);
340 while (!st.stop_requested()) {
346 auto _ = signal.try_acquire_for(invokePeriod.load(std::memory_order_acquire));
348 if (!st.stop_requested()) {
349 auto decrementOutstandingCallback = siddiqsoft::RunOnEnd {[&] {
351 outstandingCallback.fetch_sub(1, std::memory_order_release);
355 outstandingCallback.fetch_add(1, std::memory_order_release);
358 if (callback) callback();
359 invokeCounter.fetch_add(1, std::memory_order_release);
361 catch (
const std::exception& ex) {
363 std::cerr << std::format(
"Ignoring Exception (inner) in periodic_worker callback: {}", ex.what());
367 catch (
const std::exception& ex) {
369 std::cerr << std::format(
"Ignoring Exception (outer) in periodic_worker callback: {}", ex.what());
386 static void to_json(nlohmann::json& dest,
const siddiqsoft::periodic_worker<Pri>& src)