Files
salmanoff/docs/design/spinqueueing.md
T

60 lines
1.9 KiB
Markdown
Raw Normal View History

# 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.