How to atomically update a maximum value?
It doesn't seem to be possible in a single operation, but you can make a loop, that tries to do this, until it finally succeeds or value in atomic variable becomes bigger than value
:
template<typename T>
void update_maximum(std::atomic<T>& maximum_value, T const& value) noexcept
{
T prev_value = maximum_value;
while(prev_value < value &&
!maximum_value.compare_exchange_weak(prev_value, value))
{}
}
updating maximum value atomically
The strategy used to atomically update max value in a thread safe manner is correct.
Whether or not memory ordering is correct is impossible to tell because of code you are not showing.
If the atomic max value isn't used in any context other than reporting a value (i.e. no dependencies on other memory operations), you'll probably get away with std::memory_order_relaxed
.
As I mentioned in my comment, on X86
the compiler is likely to produce the same assembly instructions regardless the use of memory ordering parameters.X86
is a strongly ordered CPU which means that (by default) #LoadLoad
and #LoadStore
reordering is not allowed. therefore you won't find a (sane) compiler that will issue a memory fence around a seq_cst
load
.
(#StoreLoad
reordering is still allowed by default, but to prevent that for seq_cst
ordering is typically handled at the store
side).
As for compare_exchange_weak
(a read-modify-write operation), this requires the cache line to be locked in order to be atomic; you will see these assembly instructions on X86
: lock cmpxchg
Since this also serves as a full memory barrier, it eliminates the need for additional fences.
Note that if you use std::memory_order_relaxed
on any atomic operation, the compiler still has the freedom to apply compile time reordering
Updating a maximum value from multiple threads
Following a suggestion in a comment, I found a solution that does not require locking and instead uses the compare-and-exchange functionality found in std::atomic / boost::atomic. I am limited to C++03 so I would use boost::atomic in this case.
BOOST_STATIC_ASSERT(sizeof(int) == sizeof(float));
union FloatPun { float f; int i; };
std::vector< boost::atomic<int> > coord_max(128);
#pragma omp parallel for
for (int i = 0; i < limit; ++i) {
int j = get_coord(i);
FloatPun x, maxval;
x.f = compute_value(j, i);
maxval.i = coord_max[j].load(boost::memory_order_relaxed);
do {
if (maxval.f >= x.f) break;
} while (!coord_max[j].compare_exchange_weak(maxval.i, x.i,
boost::memory_order_relaxed));
}
There is some boilerplate involved in putting float values in ints, since it seems that atomic floats are not lock-free. I am not 100% use about the memory order, but the least restrictive level 'relaxed' seems to be OK, since non-atomic memory is not involved.
AtomicInteger and Math.max
If Java 8 is available you can use:
AtomicInteger value = new AtomicInteger(0);
Integer anotherCalculatedValue = ...;
value.getAndAccumulate(anotherCalculatedValue, Math::max);
Which from the specification will:
Atomically updates the current value with the results of
applying the given function to the current and given values,
returning the previous value.
how to update the maximum value of a slider?
In your alertesEnFonctionDuResultat()
, after you update gain
, you can add:
// et on change la valeur maximale du slider
yourSlider.maximumValue = Float(initialGains)
Anyway I think you should think again at what you are doing in your app...
For example, why here you use a text and not the value of your slider?
// on met a jour la valeur des gains initiale
initialGains = generateurDeGains + Int(sliderValueLabel.text!)!
And again, why here you update your slider maximumValue
every time the slider move?
// on donne la valeur maximale du slider qui est celle des gains générés aleatoirement
sender.maximumValue = Float(generateurDeGains)
Calculate max value in an atomic FindAndModify operation
EDIT: Upon further reflection, my original answer was correct, but wasteful. Specifically, the first step is not necessary, so here's a revised version:
You can emulate this process in two steps:
findAndModify with
_id
andmax_value
$lte
the value you're currently attempting to insert. Since_id
is unique, you know that only zero or one documents can match this query -- assuming that a document with that_id
exists, it is zero in the case where themax_value
is greater than what you're inserting, and one in the case where it is less than or equal. In the update,$push
the new value, and$set
max_value
.If and only if step #1 failed, findAndModify again with
_id
, and$push
the new value to the array. Since step #1 failed, we know that the currentmax_value
is greater than the new value, so we can ignore it and just$push
the new value.
Here's sample Python code to implement this:
# the_id is the ObjectId of the document we want to modify
# new_value is the new value to append to the list
rslt1 = rslt2 = None
rslt1 = db.collection.find_and_modify(
{'_id': the_id, 'max_value': {'$lte': new_value}},
{'$push': {'array': new_value}, '$set': {'max_value': new_value}})
if rslt1 is None:
rslt2 = db.collection.find_and_modify(
{'_id': the_id},
{'$push': {'array': new_value}})
# only one of these will be non-None; this
# picks whichever is non-None and assigns
# it to rslt
rslt = rslt1 or rslt2
(This original answer works, but the updated version above is more efficient.)
You can emulate this process in three steps:
findAndModify a document with the given
_id
and withmax_value
$gt
the current value you're attempting to insert. Since_id
is unique, you know that only zero or one documents can match this query -- assuming that a document with that_id
exists, it is zero in the case where themax_value
is less than what you're inserting, and one in the case where it is greater. The update portion for this findAndModify will$push
the new value to the array.If and only if step #1 failed, findAndModify again with
_id
andmax_value
$lte
the value you're currently attempting to insert. In the update,$push
the new value, and$set
max_value
.If and only if step #2 failed, findAndModify again with
_id
, and$push
the new value to the array. This covers the case where between steps #1 and #2, another thread upped themax_value
to a value greater than the value you're currently inserting.
Here's sample Python code to implement this:
# the_id is the ObjectId of the document we want to modify
# new_value is the new value to append to the list
rslt1 = rslt2 = rslt3 = None
rslt1 = db.collection.find_and_modify(
{'_id': the_id, 'max_value': {'$gt': new_value}},
{'$push': {'array': new_value}})
if rslt1 is None:
rslt2 = db.collection.find_and_modify(
{'_id': the_id, 'max_value': {'$lte': new_value}},
{'$push': {'array': new_value}, '$set': {'max_value': new_value}})
if rslt1 is None and rslt2 is None:
rslt3 = db.collection.find_and_modify(
{'_id': the_id},
{'$push': {'array': new_value}})
# only one of these will be non-None; this
# picks whichever is non-None and assigns
# it to rslt
rslt = rslt1 or rslt2 or rslt3
Related Topics
What Exactly Is a 'Side-Effect' in C++
Return Type Covariance with Smart Pointers
Differencebetween a MACro and a Const in C++
How to Open a Gstreamer Pipeline from Opencv with Videowriter
Differencebetween the /Ox and /O2 Compiler Options
Why Does C++11 Have 'Make_Shared' But Not 'Make_Unique'
How to Print Utf-8 Strings to Std::Cout on Windows
How Do Take a Screenshot Correctly with Xlib
Translating Python Dictionary to C++
Erasing Using Backspace Control Character
What's the Difference Between the Win32 and _Win32 Defines in C++
Public Virtual Function Derived Private in C++
How to Target Windows Xp in Microsoft Visual Studio C++
How to Get the Window Handle of the Desktop
Friend Class with Limited Access
Why Is There No Support for Concatenating Std::String and Std::String_View