60 lines
1.9 KiB
Markdown
60 lines
1.9 KiB
Markdown
|
|
# Spinqueueing: A new locking method that only blocks requests and not threads.
|
||
|
|
|
||
|
|
The idea is that instead of using sleeplocks like mutexes, we instead only spin
|
||
|
|
particular request objects by re-posting them to the queue.
|
||
|
|
|
||
|
|
Particular requests may need a given shared resource. Instead of sleeping a
|
||
|
|
whole thread while that particular request waits for the resource, we instead
|
||
|
|
sleep the request itself by re-posting it into the thread's queue. This
|
||
|
|
basically implements a kind of spinlock without busy-waiting. The underlying
|
||
|
|
thread is never blocked unless it has no requests that can make forward
|
||
|
|
progress.
|
||
|
|
|
||
|
|
Forward progress through requests is only halted when an external resource is
|
||
|
|
actually being waited on. Generally this will be an actual hardware event that
|
||
|
|
is being waited on. No software bottlenecks will be slept on.
|
||
|
|
|
||
|
|
All locks in the program are simple spinlocks, but the algorithm to spin on them
|
||
|
|
is:
|
||
|
|
|
||
|
|
## Each async call has a "locker and invoker":
|
||
|
|
|
||
|
|
int funcThatCallsAnAsyncFunc(...)
|
||
|
|
{
|
||
|
|
// Do preparatory stuff ...
|
||
|
|
|
||
|
|
|
||
|
|
// Post the lockvoker to the target thread.
|
||
|
|
targetThread.io_service.post(
|
||
|
|
[targetThread, /* args to asyncOperationReq captured here */]()
|
||
|
|
{
|
||
|
|
int nAcquired;
|
||
|
|
for (nAcquired=0; nAcquired<nLocksRequired; nAcquired++)
|
||
|
|
{
|
||
|
|
if (!requiredLocks->tryAcquire()) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (nAcquired < nLocksRequired)
|
||
|
|
{
|
||
|
|
for (int i=0; i<nAcquired; i++) {
|
||
|
|
requiredLocks->release();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Unsure how to recapture the lambda object and re-enqueue it.
|
||
|
|
* Dunno if that's even possible. But this is the essence of the
|
||
|
|
* queue-spin system. We re-enqueue the lockvoker until it
|
||
|
|
* gets all locks required. Then it will invoke the async
|
||
|
|
* frontend.
|
||
|
|
*/
|
||
|
|
targetThead.io_service.post(this?);
|
||
|
|
}
|
||
|
|
|
||
|
|
managerObject.asyncOperationReq(
|
||
|
|
/* args to asyncOperationReq passed here */);
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
## Idk how to encapsulate lockvokers into a terse, reusable idiom.
|