1 // Copyright (c) 2020 Andrey Semashev 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 // This is a fuzzing test for waiting and notifying operations. 8 // The test creates a number of threads exceeding the number of hardware threads, each of which 9 // blocks on the atomic object. The main thread then notifies one or all threads repeatedly, 10 // while incrementing the atomic object. The test ends when the atomic counter reaches the predefined limit. 11 // The goal of the test is to verify that (a) it doesn't crash and (b) all threads get unblocked in the end. 12 13 #include <boost/memory_order.hpp> 14 #include <boost/atomic/atomic.hpp> 15 16 #include <iostream> 17 #include <boost/config.hpp> 18 #include <boost/bind/bind.hpp> 19 #include <boost/chrono/chrono.hpp> 20 #include <boost/thread/thread.hpp> 21 #include <boost/thread/barrier.hpp> 22 #include <boost/smart_ptr/scoped_array.hpp> 23 24 namespace chrono = boost::chrono; 25 26 boost::atomic< unsigned int > g_atomic(0u); 27 28 BOOST_CONSTEXPR_OR_CONST unsigned int loop_count = 4096u; 29 thread_func(boost::barrier * barrier)30void thread_func(boost::barrier* barrier) 31 { 32 barrier->wait(); 33 34 unsigned int old_count = 0u; 35 while (true) 36 { 37 unsigned int new_count = g_atomic.wait(old_count, boost::memory_order_relaxed); 38 if (new_count >= loop_count) 39 break; 40 41 old_count = new_count; 42 } 43 } 44 main()45int main() 46 { 47 const unsigned int thread_count = boost::thread::hardware_concurrency() + 4u; 48 boost::barrier barrier(thread_count + 1u); 49 boost::scoped_array< boost::thread > threads(new boost::thread[thread_count]); 50 51 for (unsigned int i = 0u; i < thread_count; ++i) 52 boost::thread(boost::bind(&thread_func, &barrier)).swap(threads[i]); 53 54 barrier.wait(); 55 56 // Let the threads block on the atomic counter 57 boost::this_thread::sleep_for(chrono::milliseconds(100)); 58 59 while (true) 60 { 61 for (unsigned int i = 0u; i < thread_count; ++i) 62 { 63 g_atomic.opaque_add(1u, boost::memory_order_relaxed); 64 g_atomic.notify_one(); 65 } 66 67 unsigned int old_count = g_atomic.fetch_add(1u, boost::memory_order_relaxed); 68 g_atomic.notify_all(); 69 70 if ((old_count + 1u) >= loop_count) 71 break; 72 } 73 74 for (unsigned int i = 0u; i < thread_count; ++i) 75 threads[i].join(); 76 77 return 0u; 78 } 79