1- // Copyright (c) 2018-2019 , NVIDIA CORPORATION. All rights reserved.
1+ // Copyright (c) 2018-2025 , NVIDIA CORPORATION & AFFILIATES . All rights reserved.
22//
33// Licensed under the Apache License, Version 2.0 (the "License");
44// you may not use this file except in compliance with the License.
1717
1818#include < atomic>
1919#include < thread>
20+ #ifdef __x86_64
21+ #include < emmintrin.h>
22+ #endif
2023
2124namespace dali {
2225
@@ -26,21 +29,28 @@ namespace dali {
2629class busy_spinlock {
2730 public:
2831 void lock () noexcept {
29- while (flag_.test_and_set (std::memory_order_acquire)) {
30- // busy-wait
32+ for (;;) {
33+ bool was_locked = flag_.load (std::memory_order_relaxed);
34+ if (!was_locked && !flag_.exchange (true , std::memory_order_acquire))
35+ break ;
36+ #ifdef __x86_64
37+ _mm_pause (); // Let other hyperthreads run
38+ #endif
3139 }
3240 }
3341
3442 bool try_lock () noexcept {
35- return !flag_.test_and_set (std::memory_order_acquire);
43+ // First load the flag - if it's locked, just fail. This helps in high contention scenarios.
44+ bool was_locked = flag_.load (std::memory_order_relaxed);
45+ return !was_locked && !flag_.exchange (true , std::memory_order_acquire);
3646 }
3747
3848 void unlock () noexcept {
39- flag_.clear ( std::memory_order_release);
49+ flag_.store ( false , std::memory_order_release);
4050 }
4151
4252 private:
43- std::atomic_flag flag_ = ATOMIC_FLAG_INIT ;
53+ std::atomic< bool > flag_{ false } ;
4454};
4555
4656/* *
@@ -51,25 +61,32 @@ class yielding_spinlock {
5161 public:
5262 void lock () noexcept {
5363 int spin = yield_after_n_spins;
54- while (flag_.test_and_set (std::memory_order_acquire)) {
55- if (spin > 0 ) {
56- spin--;
64+ for (;;) {
65+ bool was_locked = flag_.load (std::memory_order_relaxed);
66+ if (!was_locked && !flag_.exchange (true , std::memory_order_acquire))
67+ break ;
68+ if (spin-- > 0 ) {
69+ #ifdef __x86_64
70+ _mm_pause (); // Let other hyperthreads run
71+ #endif
5772 } else {
5873 std::this_thread::yield ();
74+ spin = yield_after_n_spins;
5975 }
6076 }
6177 }
6278
6379 bool try_lock () noexcept {
64- return !flag_.test_and_set (std::memory_order_acquire);
80+ bool was_locked = flag_.load (std::memory_order_relaxed);
81+ return !was_locked && !flag_.exchange (true , std::memory_order_acquire);
6582 }
6683
6784 void unlock () noexcept {
68- flag_.clear ( std::memory_order_release);
85+ flag_.store ( false , std::memory_order_release);
6986 }
7087
7188 private:
72- std::atomic_flag flag_ = ATOMIC_FLAG_INIT ;
89+ std::atomic< bool > flag_{ false } ;
7390};
7491
7592using spinlock = yielding_spinlock<100 >;
0 commit comments