Reputation: 13820
I'm using C++ 11, where I have 4 threads that are parallely inserting into a concurrent queue. I know when the threads are done processing, i.e. the expected final size of the queue.
Now, I want to perform a final aggregation operation on the contents of the queue that should be strictly performed only once. For example, say I want to aggregate the values and POST it to an external service.
How do I acquire a lock which is valid only once? I can't use a simple mutex because that would not guarantee me the only once requirement.
Pseudocode:
// inside a thread
enqueue items to concurrent_queue
if(concurrent_queue.size() == EXPECTED_SIZE) {
// do something ONLY once
}
Upvotes: 2
Views: 394
Reputation: 2601
Check approach from Singleton implementations. The most basic:
bool executed = false;
void Execute()
{
Lock lock; // scope-based lock, released automatically when the function returns
if (executed == false)
{
executed = true;
//.. do computation
}
}
Check also solutions with atomic variables and double-checked locking for better performance: http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
Upvotes: 2
Reputation: 42554
If you aren't concerned about the possibility of the operation failing, you can simply use an atomic<bool>
that is associated with the operation. All of the threads will try to change the flag from false
to true
with compare_exchange_strong, but only one will succeed:
// inside a thread
enqueue items to concurrent_queue
if(concurrent_queue.size() == EXPECTED_SIZE) {
std::atomic<bool>& flag = retrieve_the_associated_bool();
bool expected = false;
if (flag.compare_exchange_strong(expected, true)) {
// do something
}
}
If the operation can fail, you should use std::call_once
and a std::once_flag
associated with the operation. The other threads will wait while one tries to "do something", and each try in turn until one succeeds:
// inside a thread
enqueue items to concurrent_queue
if(concurrent_queue.size() == EXPECTED_SIZE) {
std::once_flag& flag = retrieve_the_associated_once_flag();
std::call_once(flag, []{
// do something
});
// do something ONLY once
}
Upvotes: 2
Reputation: 16089
A simple solution.
if(concurrent_queue.size() == EXPECTED_SIZE) {
// do something ONLY once
static bool doItOnce = DoItOnceOnly();
}
Upvotes: 7