Proper way to use predicate in conditional variable - c++

I want to know if I need to reset the predicate boolean variable inside the scope of the locked mutex. Right now, I have a std::unique_lock with a lambda function as the predicate parameter - The lambda function returns a boolean flag. Does this mean I need to set the boolean flag back to false inside the scope of the lock guard?
It seems to work a lot faster if I don't reset the boolean flag, but I'm not sure if this is the safe way to approach this.
#include <thread>
#include <condition_variable>
#include <mutex>
std::condition_variable _conditional;
bool processed = false;
std::mutex _mutex;
void Worker() {
while (true) {
//Doing other things ..
//
{
//mutating shared data
std::unique_lock<std::mutex> _lock(_mutex);
_conditional.wait(_lock, [] { return processed; });
processed = false? //do I set this boolean back to false or just leave as is?
data++;
}
}
}
void Reader() {
//just prints out the changed data
while (true) {
std::cout << data << std::endl;
processed = true;
_conditional.notify_one();
}
}
int main(){
std::thread t1(Worked);
std::thread t2(Reader);
t1.join();
t2.join();
}

Firstly, the Reader never acquires a lock to synchronize its access to the shared data (in this case the processed boolean and the data variable, whatever it is) with the Worker. As such, the Reader can modify processed while the Worker is reading from it, and the Reader can read from data while the Worker is writing to it; these are both race conditions. They can be fixed by having the Reader also lock the mutex before modifying processed or reading from data. The rest of this answer assumes that this correction is made.
Secondly, whether or not processed should be reset back to false is dependent on what you want the application to do, so it's necessary to understand the consequences.
If it is never reset to false, then the Worker will never again wait on the condition variable (though it will continuously reacquire the mutex and check the value of processed, despite the fact that it is guaranteed to be true after the first wait terminates), and it will simply keep incrementing data. Even if you correctly synchronize access to the shared data like I mentioned, this still might not do what you want it to do. It's very possible that the Worker could acquire the mutex several times in a row before the Reader, and thus data can be incremented multiple times in-between prints, and data can be printed multiple times in-between increments (there is no order guarantee for printing and incrementing, in such a case)
If you reset processed back to false after each wait within the Worker, then you can guarantee that data will be printed at least once in-between each increment, since it would be unable to increment data until the Reader has notified it (which requires at least one print first). However, it may still be printed multiple times in-between each increment, because there is still no mechanism forcing the Reader to wait on the Worker.
If you provide another mechanism allowing the Reader to also wait on the Worker, then you can theoretically guarantee that each print happens exactly once in-between each increment (alternating). But once you've gone this far, the entire process is run serially, so there's really no point in using multiple threads anymore.
Notice that each of these approaches all have entirely different semantics. The one you should choose depends on what you want your application to do.

Related

c++ block thread until condition on a thread-safe object is met

I apologise in advance if my question is a duplicate, but I was not able to find a satisfying answer to my question.
I am dealing with the following (maybe silly) issue: I am trying to synchronise two threads (A and B), and I want to block the thread A until a condition is set to true by the thread B.
The "special" thing is that the condition is checked on a thread-safe object (for instance, let's consider it to be a std::atomic_bool).
My naive approach was the following:
// Shared atomic object
std::atomic_bool condition{false};
// Thread A
// ... does something
while(!condition.load()) ; // Do nothing
// Condition is met, proceed with the job
// Thread B
// ... does something
condition.store(true); // Unlock Thread A
but, as far as I have understood, the while implies an active wait which is undesirable.
So, I thought about having a small sleep_for as the body of the while to reduce the frequency of the active wait, but then the issue becomes finding the right waiting time that does not cause waste of time in case the condition unlocks while thread A is sleeping and, at the same time, does not make the loop to execute too often.
My feeling is that this is very much dependant on the time that thread B spends before setting the condition to true, which may be not predictable.
Another solution I have found looking on other SO topics is to use a condition variable, but that would require the introduction of a mutex that is not really needed.
I am perhaps overthinking the problem, but I'd like to know if there are alternative "standard" solutions to follow (bearing in mind that I am limited to C++11), and what would be the best approach in general.
Many thanks in advance for the help.
Your use case is simple and there are many ways to implement that.
The first recommendation would be to make use of condition variable. But it
seems from your question that you would like to avoid that because of mutex.
I don't have any profiling data for your use case, but mutex isn't costly for your use case.
In a multi-threaded environment, at some point of time, you would need some techniques to protect shared access and modification of data. You would probably need mutexes for that.
You could go for condition variable approach.
It is by the standard, and it also provides function to notify all the threads as well, if your use case scales in future.
Also, as you mentioned about "time", condition_variable also comes with variations of wait* functions where the condition could be in terms of "time". It can wait_for or wait_until a certain time as well.
About the while loop and a sleep_for approach, blocking a thread from execution and then rescheduling it again isn't that cheap if we are counting in terms of milliseconds. The condition variable approach would be better suited in this case, rather than having the while loop and an explicit call to sleep_for.
Sorry, condition variables are the way to go here.
The mutex is being used as a part of the condition variable, not as a traditional mutex. And barring some strange priority inversion situation, it shouldn't have much cost.
Here is a simple "farm gate". It starts shut, and can be opened. Once opened, it can never be shut again.
struct gate {
void open_gate() {
auto l = lock();
gate_is_open = true;
cv.notify_all();
}
void wait_on_gate() const {
auto l = lock();
cv.wait(l, [&]{ return gate_is_open; });
}
private:
auto lock() const { return std::unique_lock{m}; }
mutable std::mutex m;
bool gate_is_open = false;
std::condition_variable cv;
};
which you'd use like this:
// Shared gate
gate condition;
// Thread A
// ... does something
condition.wait_on_gate(); // Do nothing
// Condition is met, proceed with the job
// Thread B
// ... does something
condition.open_gate(); // Unlock Thread A
and there we have it.
In c++20 there is std::latch. Start the counter at 1, decrement it when the gate opens, and the other thread waits on the latch.
How about using some sort of a sentinel value to check if the conditions of thread B are true to unlock thread A and synchronize both of them once the condition is met.

Join threads created recursively

I have a function that basically fetches a data from a database, then parse this data and fetches others data to which it is dependant, and so on...
The function is thus recursive, and I want to use multithreading to do so.
To simplify the problem, I just writed a dummy program, just for expressing the "spirit" of the function:
void DummyFunction(std::vector<std::thread>& threads, int& i)
{
++i;
if (i < 10)
threads.push_back(std::thread([&]() { DummyFunction(threads, i); }));
}
int main()
{
std::vector<std::thread> threads;
int i = 0;
DummyFunction(threads, i);
// Coming here, "DummyFunction" is still running and potentially creating new threads
// Issue is thus we may enter the for loop when we still don't have the actual number of threads created
for (std::thread& thread : threads)
{
thread.join();
}
}
The issue comes from the need to wait for all the threads to finish running before going any further (hence the for loop to join the threads). But of course, since the "DummyFunction" is still running, new threads can be created and so this way it can't work...
Question is, how can I design such thing properly (if there is a way...)? Can we actually use multi threading recursively?
If you have C++20 available consider using the new thread that automatically joins on destruction. It goes by the name jthread and will save you all the trouble from having to manually join threads.
Try a thought experiment: add an else clause to your if statement:
if (i < 10)
{
threads.push_back(std::thread([&]() { DummyFunction(threads, i); }));
}
else
{
// do something here
}
Once you make that change, a few minutes' worth of thinking will reach the following conclusion: the "do something here" part gets executed exactly once, in one of the execution threads, after all of the execution threads get created.
Now, the solution should be very obvious:
Add a mutex, a condition variable, and a boolean flag. You can either make them global; pass them as additional parameters into DummyFunction, or, better yet: turn your threads vector into its own class containing the vector, the mutex, the condition variable, and the boolean flag, and pass that in recursively instead of just the vector.
main() locks the mutex, clears the condition variable, and after DummyFunction() returns it waits on the condition variable until the boolean flag is set.
The "do something here" part locks the same mutex, sets the boolean flag, signals the condition variable, and unlocks the mutex.
Once you reach this point, you will also suddenly realize one more thing: as is, you have different execution threads all attempting to push_back something into the same vector. Vectors are not thread-safe, so this is undefined behavior. Therefore, you will also need to implement a separate mutex (or reuse the existing one, this looks eminently possible to me) to also lock the access to the vector.

Trying to minimize checks of atomics on every iteration

From a multithreading perspective, is the following correct or incorrect?
I have an app which has 2 threads: the main thread, and a worker thread.
The main thread has a MainUpdate() function that gets called in a continuous loop. As part of its job, that MainUpdate() function might call a ToggleActive() method on the worker objects running on the worker thread. That ToggleActive() method is used to turn the worker objects on/off.
The flow is something like this.
// MainThread
while(true) {
MainUpdate(...);
}
void MainUpdate(...) {
for(auto& obj: objectsInWorkerThread) {
if (foo())
obj.ToggleActive(getBool());
}
}
// Worker thread example worker ------------------------------
struct SomeWorkerObject {
void Execute(...) {
if(mIsActive == false) // %%%%%%% THIS!
return;
Update(...);
}
void ToggleActive(bool active) {
mIsActiveAtom = active; // %%%%%%% THIS!
mIsActive = mIsActiveAtom; // %%%%%%% THIS!
}
private:
void Update(...) {...}
std::atomic_bool mIsActiveAtom = true;
volatile bool mIsActive = true;
};
I'm trying to avoid checking the atomic field on every invocation of Execute(), which gets called on every iteration of the worker thread. There are many worker objects running at any one time, and thus there would be many atomic fields checks.
As you can see, I'm using the non-atomic field to check for activeness. The value of the non-atomic field gets its value from the atomic field in ToggleActive().
From my tests, this seems to be working, but I have a feeling that it is incorrect.
volatile variable only guarantees that it is not optimized out and reorder by compiler and has nothing to do with multi-thread execution. Therefore, your program does have race condition since ToggleActive and Execute can modify/read mIsActive at the same time.
About performance, you can check if your platform support for lock-free atomic bool. If that is the case, checking atomic value can be very fast. I remember seeing a benchmark somewhere that show std::atomic<bool> has the same speed as volatile bool.
#hgminh is right, your code is not safe.
Synchronization is two way road — if you have a thread perform thread-safe write, another thread must perform thread-safe read. If you have a thread use a lock, another thread must use the same lock.
Think about inter-thread communication as message passing (incidentally, it works exactly that way in modern CPUs). If both sides don't share a messaging channel (mIsActiveAtom), the message might not be delivered properly.

How do I make a thread wait without polling?

I have question about multi threading in c++. I have a scenario as follows
void ThreadedRead(int32_t thread_num, BinReader reader) {
while (!reader.endOfData) {
thread_buckets[thread_num].clear();
thread_buckets[thread_num] = reader.readnextbatch()
thread_flags[thread_num] = THREAD_WAITING;
while (thread_flags[thread_num] != THREAD_RUNNING) {
// wait until awakened
if (thread_flags[thread_num] != THREAD_RUNNING) {
//go back to sleep
}
}
}
thread_flags[thread_num] = THREAD_FINISHED;
}
No section of the above code writes or access memory shared between threads. Each thread is assigned a thread_num and a unique reader object that it may use to read data.
I want the main thread to be able to notify a thread that is in the THREAD_WAITING state that his state has been changed back to THREAD_RUNNING and he needs to do some work. I don't want to him to keep polling his state.
I understand conditional vars and mutexes can help me. But I'm not sure how to use them because I don't want to acquire or need a lock. How can the mainthread blanket notify all waiting threads that they are now free to read more data?
EDIT:
Just in case anyone needs more details
1) reader reads some files
2) thread_buckets is a vector of vectors of uint16
3) threadflags is a int vector
they have all been resized appropriately
I realize that you wrote that you wanted to avoid condition variables and locks. On the other hand you mentioned that this was because you were not sure about how to use them. Please consider the following example to get the job done without polling:
The trick with the condition variables is that a single condition_variable object together with a single mutex object will do the management for you including the handling of the unique_lock objects in the worker threads. Since you tagged your question as C++ I assume you are talking about C++11 (or higher) multithreading (I guess that C-pthreads may work similarly). Your code could be as follows:
// compile for C++11 or higher
#include <thread>
#include <condition_variable>
#include <mutex>
// objects visible to both master and workers:
std::condition_variable cvr;
std::mutex mtx;
void ThreadedRead(int32_t thread_num, BinReader reader) {
while (!reader.endOfData) {
thread_buckets[thread_num].clear();
thread_buckets[thread_num] = reader.readnextbatch()
std::unique_lock<std::mutex> myLock(mtx);
// This lock will be managed by the condition variable!
thread_flags[thread_num] = THREAD_WAITING;
while (thread_flags[thread_num] == THREAD_WAITING) {
cvr.wait(myLock);
// ...must be in a loop as shown because of potential spurious wake-ups
}
}
thread_flags[thread_num] = THREAD_FINISHED;
}
To (re-)activate the workers from a master thread:
{ // block...
// step 1: usually make sure that there is no worker still preparing itself at the moment
std::unique_lock<std::mutex> someLock(mtx);
// (in your case this would not cover workers currently busy with reader.readnextbatch(),
// these would be not re-started this time...)
// step 2: set all worker threads that should work now to THREAD_RUNNING
for (...looping over the worker's flags...) {
if (...corresponding worker should run now...) {
flag = THREAD_RUNNING;
}
}
// step 3: signalize the workers to run now
cvr.notify_all();
} // ...block, releasing someLock
Notice:
If you just want to trigger all sleeping workers you should control them with a single flag instead of a container of flags.
If you want to trigger single sleeping workers but it doesn't matter which one consider the .notify_one() member function instead of .notify_all(). Note as well that also in this case a single mutex/condition_variable pair is sufficient.
The flags should better be placed in an atomic object such as a global std::atomic<int> or maybe for finer control in a std::vector<std::atomic<int>>.
A good introduction to std::condition_variable which also inspired the suggested solution is given in: cplusplus website
It looks like there are a few issues. For one thing, you do not need the conditional inside of your loop:
while (thread_flags[thread_num] != THREAD_RUNNING);
will work by itself. As soon as that condition is false, the loop will exit.
If all you want to do is avoid checking thread_flags as quickly as possible, just put a yield in the loop:
while (thread_flags[thread_num] != THREAD_RUNNING) yield(100);
This will cause the thread to yield the CPU so that it can do other things while the thread waits for its state to change. This will make make the overhead for polling close to negligible. You can experiment with the sleep duration to find a good value. 100ms is probably on the long side.
Depending on what causes the thread state to change, you could have the thread poll that condition/value directly (with a sleep in still) and not bother with states at all.
There are a lot of options here. If you look up reader threads you can probably find just what you want; having a separate reader thread is very common.

waiting on past events

I have a C++ program with a test class with two methods:
void IntegrationTestBase::wait_test_end() {
unique_lock<mutex> lock(m_mutex);
m_cond.wait(lock);
}
void IntegrationTestBase::notify_test_end() {
XN_LOGF_ITEST_BASE(INFO, "Test end");
m_cond.notify_all();
m_cond is a conditional variable, m_mutex is mutex.
The flow is that an unknow number of threads might wait_test_end and then some other thread might notify_test_end and they will all stop waiting.
The problem is that after notify_test_end some other threads might wait_test_end and they will be stuck in the wait indefinitly.
How can I cope with this?
The way to cope with it is understand what condition variable is and what it is not. In particular, it is not a singalling mechanism.
Condition variable protect a certain resource (a real variable, for example). The pattern of using it is always the same:
Lock the mutex
Check the real variable to see if it contains the value you are interested in
If not, wait on condition variable - if yes, use the variable and unlock the mutex.