Docs: update qutex algo plan
This commit is contained in:
+64
-20
@@ -257,6 +257,25 @@ class LockSet
|
||||
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
|
||||
{
|
||||
public:
|
||||
@@ -280,17 +299,27 @@ public:
|
||||
return it;
|
||||
}
|
||||
|
||||
void unregister(LockerAndInvokerList::iterator it)
|
||||
void unregister(LockerAndInvokerList::iterator it, bool shouldLock=1)
|
||||
{
|
||||
lock.acquire();
|
||||
queue.erase(it);
|
||||
lock.release();
|
||||
if (shouldLock)
|
||||
{
|
||||
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();
|
||||
qNItems = queue.size();
|
||||
|
||||
const qNItems = queue.size();
|
||||
|
||||
if (qNItems < 1) {
|
||||
lock.release();
|
||||
@@ -304,17 +333,11 @@ public:
|
||||
throw;
|
||||
}
|
||||
|
||||
if (isOwned) {
|
||||
if (!!currentOwner) {
|
||||
lock.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nRequiredLocks == 1) {
|
||||
isOwned.store(true);
|
||||
lock.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** EXPLANATION:
|
||||
* From here:
|
||||
* 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;
|
||||
|
||||
if (qNItems == 1 || nRearItemsToScan < 1) {
|
||||
isOwned.store(true);
|
||||
currOwner = tryingLockvoker;
|
||||
lock.release();
|
||||
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 rEndIt = queue.rend();
|
||||
bool foundInRear = false;
|
||||
for (int i=0; i<nRearItemsToScan && rIt != rEndIt; rIt++, i++)
|
||||
{
|
||||
if (&(*rIt) != &tryingLockvoker) { continue; }
|
||||
if (*rIt != tryingLockvoker) { continue; }
|
||||
|
||||
foundInRear == true;
|
||||
break;
|
||||
@@ -364,7 +401,7 @@ public:
|
||||
/* Not found in rear: this means the item is in the top X%. That means
|
||||
* it should be allowed to claim the lock.
|
||||
*/
|
||||
isOwned.store(true);
|
||||
currOwner = tryingLockvoker;
|
||||
lock.release();
|
||||
return true;
|
||||
}
|
||||
@@ -445,6 +482,8 @@ public:
|
||||
*/
|
||||
}
|
||||
|
||||
currOwner.release();
|
||||
|
||||
LockerAndInvoker &newFront = queue.front();
|
||||
|
||||
lock.release();
|
||||
@@ -452,7 +491,7 @@ public:
|
||||
wakeUp(newFront);
|
||||
}
|
||||
|
||||
void release(LockerAndInvoker &prevOwner)
|
||||
void release()
|
||||
{
|
||||
lock.acquire();
|
||||
|
||||
@@ -460,8 +499,13 @@ public:
|
||||
LockerAndInvoker &oldFront = queue.front();
|
||||
#endif
|
||||
|
||||
unregister(prevOwner.serializedContinuation.requiredLocks.getDesc(
|
||||
*this).second);
|
||||
/* Get the saved iterator and use it to unregister.
|
||||
* Don't acquire lock because we already acquired it in this function.
|
||||
*/
|
||||
unregister(currOwner->serializedContinuation.requiredLocks
|
||||
.getLockUsageDesc(*this).second, false);
|
||||
|
||||
currOwner.release();
|
||||
|
||||
/** NOTE:
|
||||
* I am not sure whether we should only wake up the front item if
|
||||
@@ -514,7 +558,7 @@ public:
|
||||
|
||||
public:
|
||||
SpinLock lock;
|
||||
std::atomic<bool> isOwned;
|
||||
std::shared_ptr<LockerAndInvoker> currOwner;
|
||||
LockerAndInvokerList queue;
|
||||
};
|
||||
```
|
||||
Reference in New Issue
Block a user