Docs: update qutex algo plan

This commit is contained in:
2025-09-19 18:52:27 -04:00
parent 4b0e832e27
commit d10217f3f5
+64 -20
View File
@@ -257,6 +257,25 @@ class LockSet
std::vector<LockUsageDesc> locks; std::vector<LockUsageDesc> locks;
} }
bool LockerAndInvoker::operator==(const LockerAndInvoker &other)
{
/* Compare by the address of the continuation objects. Why?
* Because there's no guarantee that the lockvoker object that was
* passed in by the io_service invocation is the same object as that
* which is in the qutexQs. Especially because we make_shared() a
* copy when registerInQutexQueues()ing.
*
* Generally when we "wake" a lockvoker by enqueuing it, boost's
* io_service::post will copy the lockvoker object.
*/
return &this->serializedContinuation == &other.serializedContinuation;
}
bool LockerAndInvoker::operator !=(const LockerAndInvoker &other)
{
return &this->serializedContinuation != &other.serializedContinuation;
}
class Qutex class Qutex
{ {
public: public:
@@ -280,17 +299,27 @@ public:
return it; return it;
} }
void unregister(LockerAndInvokerList::iterator it) void unregister(LockerAndInvokerList::iterator it, bool shouldLock=1)
{ {
lock.acquire(); if (shouldLock)
queue.erase(it); {
lock.release(); lock.acquire();
queue.erase(it);
lock.release();
}
else{
queue.erase(it);
}
} }
bool tryAcquire(LockerAndInvoker &tryingLockvoker, int nRequiredLocks) bool tryAcquire(LockerAndInvoker &tryingLockvoker)
{ {
const nRequiredLocks = tryingLockvoker.serializedContinuation
.requiredLocks.size();
lock.acquire(); lock.acquire();
qNItems = queue.size();
const qNItems = queue.size();
if (qNItems < 1) { if (qNItems < 1) {
lock.release(); lock.release();
@@ -304,17 +333,11 @@ public:
throw; throw;
} }
if (isOwned) { if (!!currentOwner) {
lock.release(); lock.release();
return false; return false;
} }
if (nRequiredLocks == 1) {
isOwned.store(true);
lock.release();
return true;
}
/** EXPLANATION: /** EXPLANATION:
* From here: * From here:
* if qNItems == 1 the we are the only one in the ticketQ and we have * if qNItems == 1 the we are the only one in the ticketQ and we have
@@ -340,17 +363,31 @@ public:
const int nRearItemsToScan = qNItems / nRequiredLocks; const int nRearItemsToScan = qNItems / nRequiredLocks;
if (qNItems == 1 || nRearItemsToScan < 1) { if (qNItems == 1 || nRearItemsToScan < 1) {
isOwned.store(true); currOwner = tryingLockvoker;
lock.release(); lock.release();
return true; return true;
} }
/** EXPLANATION:
* For lockvokers that only have 1 requiredLock, they must be at the
* front of the queue to successfully acquire.
*/
if (nRequiredLocks == 1)
{
if (tryingLockvoker == &queue.front())
{
currOwner = tryingLockvoker;
lock.release();
return true;
}
}
auto rIt = queue.rbegin(); auto rIt = queue.rbegin();
auto rEndIt = queue.rend(); auto rEndIt = queue.rend();
bool foundInRear = false; bool foundInRear = false;
for (int i=0; i<nRearItemsToScan && rIt != rEndIt; rIt++, i++) for (int i=0; i<nRearItemsToScan && rIt != rEndIt; rIt++, i++)
{ {
if (&(*rIt) != &tryingLockvoker) { continue; } if (*rIt != tryingLockvoker) { continue; }
foundInRear == true; foundInRear == true;
break; break;
@@ -364,7 +401,7 @@ public:
/* Not found in rear: this means the item is in the top X%. That means /* Not found in rear: this means the item is in the top X%. That means
* it should be allowed to claim the lock. * it should be allowed to claim the lock.
*/ */
isOwned.store(true); currOwner = tryingLockvoker;
lock.release(); lock.release();
return true; return true;
} }
@@ -445,6 +482,8 @@ public:
*/ */
} }
currOwner.release();
LockerAndInvoker &newFront = queue.front(); LockerAndInvoker &newFront = queue.front();
lock.release(); lock.release();
@@ -452,7 +491,7 @@ public:
wakeUp(newFront); wakeUp(newFront);
} }
void release(LockerAndInvoker &prevOwner) void release()
{ {
lock.acquire(); lock.acquire();
@@ -460,8 +499,13 @@ public:
LockerAndInvoker &oldFront = queue.front(); LockerAndInvoker &oldFront = queue.front();
#endif #endif
unregister(prevOwner.serializedContinuation.requiredLocks.getDesc( /* Get the saved iterator and use it to unregister.
*this).second); * Don't acquire lock because we already acquired it in this function.
*/
unregister(currOwner->serializedContinuation.requiredLocks
.getLockUsageDesc(*this).second, false);
currOwner.release();
/** NOTE: /** NOTE:
* I am not sure whether we should only wake up the front item if * I am not sure whether we should only wake up the front item if
@@ -514,7 +558,7 @@ public:
public: public:
SpinLock lock; SpinLock lock;
std::atomic<bool> isOwned; std::shared_ptr<LockerAndInvoker> currOwner;
LockerAndInvokerList queue; LockerAndInvokerList queue;
}; };
``` ```