Is it the max allowed value of the inner counter
? But how is it possible to talk about minimum max value? Shouldn't max
value be const? How can it be changed? What is difference between LeastMaxValue
and counter
?
As its name indicates, the LeastMaxValue is the minimum max value, not the actual max value. Thus max() can yield a number larger than LeastMaxValue. https://en.cppreference.com/w/cpp/thread/counting_semaphore/max
The constructor call
std::counting_semaphore<10> sem(5)
creates a semaphore sem with an at least maximal value of 10 and a counter of 5. https://www.modernescpp.com/index.php/semaphores-in-c-20
CodePudding user response:
Shouldn't max value be const?
Yes. In fact, counting_semaphore<LeastMaxValue>::max()
is required to be constexpr
, meaning that it is not just constant, but a compile-time constant. For a given LeastMaxValue
, the max
can vary from compilation to compilation, but no more than that.
Perhaps that's the source of your confusion? From the perspective of watching a program run, the max()
corresponding to a given LeastMaxValue
is constant. From the perspective of making sure code works across multiple compilers and platforms, max()
can vary.
When you declare a variable whose type is std::counting_semaphore<5>
, you are declaring that the variable's counter will need to go up to 5
. This becomes a request to the compiler that the counter be able to hold 5
. If it happens that the counter can hold 255
, well that's fine. You don't plan to raise the counter that high, so your code will function correctly with that maximum.
Look at the constructor of std::counting_semaphore<LeastMaxValue>
. This will function correctly as long as the initial value of the counter satisfies 0 <= initial
and initial <= max()
. The first condition is easy to satisfy, but how do you satisfy the second? You can do this by satisfying a more stringent requirement – make sure initial <= LeastMaxValue
. This is more stringent, because the compiler is obligated to ensure that for your choice of LeastMaxValue
, the corresponding max()
is at least as large; that is, LeastMaxValue <= max()
. As long as you specify a high enough value for LeastMaxValue
, the constructor will work as intended with your initial value.
There is a similar requirement for release()
to function correctly. Correct behavior requires that the counter not exceed max()
, which you can ensure by not exceeding LeastMaxValue
. You do get correct behavior if the counter ends up between LeastMaxValue
and max()
, but then you are subject to the whims of your compiler. A different compiler might give you a lower max()
. If you want to play in this area, your code needs to adapt to a max()
that can change from compiler version to compiler version.
You could think of this as being similar to int_fast8_t
in that the 8
specifies the minimum size of the type, but the compiler can give you more. You are guaranteed that the maximum value that can be stored in this type is at least 127
(the minimum max value). You might get more than 8 bits in this type, and hence be able to store higher values, but you might not.