Am 23.09.2021 um 19:38 schrieb Chris M. Thomasson:
> On 9/20/2021 1:43 PM, Bonita Montero wrote:
>> In some code I've to check different sates for which an exception might
>> be thrown. These states are all true or false so I combined them to a
>> four bit pattern wich I used as an index to a table which stores the
>> strings of the out_of_range exception to be trown or a nullptr if the
>> state isn't associated with an out of range condition. This helps me
>> to prevent some if-else-cascades and speeds up the code.
>> So this is the complete function but i put two empty lines around the
>> code I mentioned.
>>
>> void dual_monitor::wait( bool b )
> [...]
>
> Please, try it out in a race detector? Create several programs that use
> your code in high load scenarios, and see what happens in the detector.
> Do we all have the time to examine your "tricky" code and test it out
> for ourselves? Well, not really. I am fairly busy with some fractal work
> right now. Sorry Bonita.
Not necessary. My montor works perfectly.
I've implemented something completely new: a poll_wait operation.
You simply supply a check-lambda that checks if there is valid state
and my code repeatedly tries to lock the lock and check if the con-
dition is true. The number of spins is re-calculated at each call
according to the recalculation-pattern of the glibc.
template<typename RetType, typename Predicate>
requires requires( Predicate pred )
{
{ pred() } -> std::same_as<std::pair<bool, RetType>>;
}
RetType monitor::wait_poll( Predicate const &pred )
{
using namespace std;
using retpair_t = pair<bool, RetType>;
uint32_t maxSpinT = (uint32_t)m_nextPollSpinCount * 2 + 10;
uint16_t maxSpin = maxSpinT <= m_maxPollSpinCount ?
(uint16_t)maxSpinT : m_maxPollSpinCount,
spinCount = 0;
bool notify = false;
uint64_t cmp = m_flagAndCounters.load( memory_order_relaxed );
for( ; !notify && spinCount < maxSpin; ++spinCount )
if( isOwned( cmp ) )
{
cpu_pause( PAUSE_ITERATIONS );
cmp = m_flagAndCounters.load( memory_order_relaxed );
continue;
}
else if( m_flagAndCounters.compare_exchange_weak( cmp, cmp |
OWNER_MASK, memory_order_acquire, memory_order_relaxed ) )
{
retpair_t ret = move( pred() );
uint64_t chg;
do
{
uint32_t visitors = getVisitors( cmp ),
waiters = getWaiters( cmp );
assert(visitors >= waiters);
chg = cmp & ~OWNER_MASK;
if( notify = visitors > waiters )
chg -= VISITOR_VALUE;
} while( !m_flagAndCounters.compare_exchange_weak( cmp, chg,
memory_order_relaxed, memory_order_relaxed ) );
if( notify )
#if defined(_MSC_VER)
while( !SetEvent( (HANDLE)m_xhEvtVisit ) );
#elif defined(__unix__)
for( m_sems( { sembuf( VISITOR_SEM, 1, 0 ) }, false ) == -1 );
#endif
if( !ret.first )
if( !notify )
continue;
else
break;
if( !notify )
m_nextPollSpinCount += (int16_t)(((int32_t)spinCount -
(int32_t)m_nextPollSpinCount) / 8);
return move( ret.second );
}
else
cpu_pause( PAUSE_ITERATIONS );
if( !notify )
m_nextPollSpinCount += (int16_t)(((int32_t)spinCount -
(int32_t)m_nextPollSpinCount) / 8);
lock();
try
{
for( ; ; )
{
retpair_t ret = move( pred() );
if( ret.first )
{
unlock();
return move( ret.second );
}
wait();
}
}
catch( ... )
{
unlock();
throw;
}
}