The constructor of lock_upgrade()upgrade_lock
is not thread-safenever locks the mutex
Imagine two threads callingWhen constructing an lock_upgrade()upgrade_lock
at the same time. Both threads think there are only readers at that pointvariable, so they both set the state toconstructor sets rip_parallel::upgrade_statem_state = initial_state
, they both decrement before calling either m_readerslock_shared()
, then increment or m_upgraderslock_unique()
. In the latter two functions, it checks the current value of m_mutex.readers_count()m_state
will, and if it already matches the target state, these functions immediately return.
lock_upgrade()
is only safe if mutexes are only accessed via upgrade_lock
s
The function 0lock_upgrade()
has a while loop that waits for both threads, and then they bothreaders to become zero. The assumption being that no new read locks can be acquired after the call to m_mutex.upgrade_lockdisable_read()
. Now you have two threads thinking they have exclusiveHowever, that only works if the only access to a mutex is via the upgrade_lock()
class. It doesn't matter thatIf someone calls m_readersmutex.lock_shared()
directly between the end of the while-loop and before m_upgradersupgrade()
are atomic here!is called, then the read lock will be successfully acquired.