3 ms·
Could you build on the always-unfair system along these lines? (C11ish, sorry) void do_work(the_work_t *w) { /* for simplicity here, rather than e
by raattgift 8y ago
Could you build on the always-unfair system along these lines? (C11ish, sorry)
void
do_work(the_work_t *w)
{
/* for simplicity here, rather than e.g. w->contenders */
static _Atomic int contenders = 0;
contenders++;
for ( ; work_remaining(w); ) {
take_mutex(w->m);
do_some_work(w);
drop_mutex(w->m);
if (contenders > 1)
reschedule_this_thread();
}
contenders--;
}
This depends on the OS providing a cheap and fast reschedule_this_thread() mechanism that effectively guarantees that if there is only one other contending thread with work, that thread will end up holding the mutex. (If there are multiple such threads, an arbitrary one of them will end up with the mutex, rather than the thread that just dropped the mutex.)
One could of course only check for other contenders every few times through the for loop if reschedule_this_thread() is expensive or slow, or if contenders is especially hot.
contenders is explicitly not a locking mechanism and should not influence the policy of any code running while the mutex is held. It should also be a per-mutex counter.
- brucedawson 8y agoThe trick is how you implement reschedule this thread. What you want in this specific case is to take it off-core long enough for another thread to wake up and take the lock. That is far too squishy a goal to be something that you can implement. If you sleep for some number of nanoseconds then you are wasting performance and/or not sleeping long enough. In this particular case the lock was a kernel lock in kernel code so the OS would have to fix this, by making the locks fair (or occasionally fair).
- raattgift 8y agoI've been spoiled by a better OS. :D How about: while work: if (contenders > 1) { reduce_priority; pri_reduced = true } take_lock if (pri_reduced) { unreduce_priority; pri_reduced = false } do_work_quantum drop_lock endwhile (I mean empirically, although an educated guess would do). Of course, if reducing priority is too fast, this likely doesn't help; alternatively it could be too slow and what you get back in system latency is taken away in lowered throughput. That's probably not OK if you don't need the system latency to be low. I wonder if (dramatically, even) reducing the priority of some of the original workload exposing the problem, not just when racing for a lock but when doing the actual work quanta, would help. My thought here is that your email-sending is higher-prirority and will at least push some of the workload out of the way in reasonable time, giving you back some responsiveness. I'm surprised if Windows doesn't offer up a high-throughput/latency-tolerant QOS for threads.
- brucedawson 8y agoPriorities don't help. They are only relevant if there are more runnable threads than CPUs. In my case I had lots of spare CPUs so both threads could run, regardless of priority. A QOS does not directly help. The only thing I am aware of that can help is fair locks, or occasionally fair locks, so that the lock is given directly to the waiting thread, instead of being made available to all. I have yet to hear of any other solutions.
- kayamon 8y agoSee here for a good ticketing mutex that fairly solves the problem: - https://stackoverflow.com/a/5386266 https://stackoverflow.com/a/5386266