| 15 | #include "fl/stl/vector.h" |
| 16 | |
| 17 | FL_TEST_FILE(FL_FILEPATH) { |
| 18 | |
| 19 | #if FASTLED_MULTITHREADED |
| 20 | |
| 21 | |
| 22 | FL_TEST_CASE("fl::condition_variable basic operations") { |
| 23 | fl::mutex mtx; |
| 24 | fl::condition_variable cv; |
| 25 | fl::atomic<bool> ready(false); |
| 26 | fl::atomic<bool> processed(false); |
| 27 | |
| 28 | FL_SUBCASE("notify_one wakes waiting thread") { |
| 29 | std::thread worker([&]() { // okay std namespace - fl::thread not available |
| 30 | fl::unique_lock<fl::mutex> lock(mtx); |
| 31 | ready.store(true); |
| 32 | cv.notify_one(); // Signal main thread |
| 33 | |
| 34 | // Wait for main thread to process |
| 35 | cv.wait(lock, [&]() { return processed.load(); }); |
| 36 | }); |
| 37 | |
| 38 | // Wait for worker to be ready |
| 39 | fl::unique_lock<fl::mutex> lock(mtx); |
| 40 | cv.wait(lock, [&]() { return ready.load(); }); |
| 41 | |
| 42 | // Signal we've processed |
| 43 | processed.store(true); |
| 44 | cv.notify_one(); |
| 45 | |
| 46 | lock.unlock(); |
| 47 | worker.join(); |
| 48 | |
| 49 | FL_CHECK(ready.load() == true); |
| 50 | FL_CHECK(processed.load() == true); |
| 51 | } |
| 52 | |
| 53 | FL_SUBCASE("notify_all wakes multiple threads") { |
| 54 | constexpr int num_threads = 3; |
| 55 | fl::atomic<int> wake_count(0); |
| 56 | fl::vector<std::thread> threads; // okay std namespace - fl::thread not available |
| 57 | |
| 58 | for (int i = 0; i < num_threads; ++i) { |
| 59 | threads.push_back(std::thread([&]() { // okay std namespace |
| 60 | fl::unique_lock<fl::mutex> lock(mtx); |
| 61 | cv.wait(lock, [&]() { return ready.load(); }); |
| 62 | wake_count.fetch_add(1); |
| 63 | })); |
| 64 | } |
| 65 | |
| 66 | // Give threads time to start waiting (reduced from 10ms to 5ms for performance) |
| 67 | fl::delay(5); |
| 68 | |
| 69 | // Wake all threads |
| 70 | { |
| 71 | fl::unique_lock<fl::mutex> lock(mtx); |
| 72 | ready.store(true); |
| 73 | } |
| 74 | cv.notify_all(); |
nothing calls this directly
no test coverage detected