C++ Equivalent of SpinWait.SpinUntil
I like to use threads in my code, but the problem with threads is that sometimes you need to wait for them to finish.
In c++ it is very easy to do.
1 2 3 4 |
std::thread t (my_function,1); // do something // do something else t.join(); |
All the code above does is, start a thread, call the function my_function
and passes the argument 1
.
The t.join();
tells the main thread to wait until the thread is finished.
Now the problem is that t.join()
could hang forever … and I would never know about it.
What I needed was something like join_until( 1000)
where we either wait for the thread to finish or wait for 1000ms. What I needed was something similar to c# SpinUntil
In very simple terms all SpinUntil
does is check a condition, (very often), and if it is true then return (true), but if a timeout happens then we return (false).
So in my case I would wait for the thread to complete, (yes I know, I know, you can’t easily tell if a std::thread is complete or not.
Enter Wait.SpinUntil …
1 2 3 4 |
static bool SpinUntil(std::function<bool()> condition, const long long milliseconds) { // magic } |
Basically we will
- Start a new thread
- Check if the given condition is true
- If the condition is true, return true
- If the condition is false … continue.
- Wait for a couple of nanoseconds for other threads to do their bit
- Look how long we have been spinning
- If less than
milliseconds
go back to number 2 - If more than
milliseconds
, return false.
- If less than
The code
This is a very simplified version of the code, you can find a working solution on my github page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
// this code is inside our running thread // while we will join our thread, it is possible for it to block, (see below) { // assume that we will timeout bool result = false; std::unique_lock<std::mutex> lock(_mutex); try { // one ms wait. const auto oneMillisecond = std::chrono::milliseconds(1); // when we want to sleep until. const auto until = std::chrono::high_resolution_clock::now() + std::chrono::milliseconds(milliseconds); for (auto count = 0; count < std::numeric_limits<int>::max(); ++count) { if (condition()) { // we have not timeout! result = true; break; } if (count % 4 == 0) { // slee a little bit std::this_thread::sleep_for(oneMillisecond); } else { // yield. std::this_thread::yield(); } // are we done? if (std::chrono::high_resolution_clock::now() >= until) { break; } } } } catch(...) { // something broke ... maybe we should re-throw. result = false; } // return the result return result; } |
So now the code above will wait for a couple of ms while running in the background and if the given condition is true we will get out and return true, otherwise we will return false after a while.
Possible issues
- For one thing, the
condition()
function could hang, it is up to the caller to make sure this never happens. - The
condition()
function could take a rather long time to execute … it is up to the caller to make sure this never happens
In other words, don’t stuff things up in your condition()
function.
Recent Comments