Actions
Bug #21840
openLocking a mutex can lead to starvation
Bug #21840:
Locking a mutex can lead to starvation
Description
Continually locking a mutex m can lead to starvation if all other threads are on the waitq of m.
Let T be the thread that keeps on acquiring mutex m in a loop.
Iteration 1:
-
Tlocks mutexm - All other threads attempt to acquire
mand end up on its waitq -
Treleases the GVL, doesn't wake any other threads because they're all waiting onm -
Treturns from the blocking function, resets itsrunning_timeto 0, acquires the GVL and continues running -
Tunlocksm. It adds the head of the waitq (T2) to the thread readyq.Tcontinues running
Iteration 2:
-
Tlocks mutexm -
Tcalls a blocking function. This time, it dequeues the readyq (ex:T2) and sends it the wakeup signal.Truns its blocking function -
T2wakes up, acquires the GVL and attempts to lock mutexm. It fails and goes back asleep, putting itself back on the waitq ofm. -
Treturns from the blocking function, sets itsrunning_timeback to 0, acquires the GVL and keeps running -
Tunlocksm. It adds the head of the waitq (ex:T3) to the end of the thread readyq.Tcontinues running. Repeat Iteration 2 except the head of readyq is nowT3
The problem is that T can never be pre-empted.
Example script:
m = Mutex.new
def fib(n)
return n if n <= 1
fib(n - 1) + fib(n - 2)
end
t1_running = false
t1 = Thread.new do
t1_running = true
loop do
fib(20)
m.synchronize do
$stderr.puts "t1 iter"
end
end
end
loop until t1_running
5.times.map do
Thread.new do
m.synchronize do
end
end
end.each(&:join)
No data to display
Actions