I want to release the GIL

"Martin v. Löwis" martin at v.loewis.de
Tue Oct 21 16:32:51 EDT 2008


> When I run it, I notice that only one thread works and the other one 
> never has a chance to run. I guess it is because the thread don't
> have a chance to release the GIL

This guess is wrong. A call to lock.acquire *does* release the GIL,
(as does the call to thread.sleep, as somebody else pointed out).

The real problem is that thread.lock is not guaranteed to be fair
(and isn't fair on most operating systems).

What happens is this (slight variations possible)

thread 1               thread 2
acquire GIL            (wait for GIL)

release GIL                               (OS might schedule thread 2
                                           here, but typically won't)
acquire lock
acquire GIL

print ident

release GIL
sleep                 acquire GIL
                      release GIL
                      (wait for lock)     (still hold by thread 1)
(wait for GIL)
acquire GIL

release lock

release GIL
(wait for lock)                       (both threads waiting for
                                       lock here. OS choses thread 1)
acquire lock
acquire GIL

(and so on)

To make that work the way you want it, you need a fair wake-up order.
Here is an example, using a list of Event objects:

import time
import threading

events = []

def f(e):
    while True:
        events.append(e)
        token = e.wait()
        e.clear()
        print threading.currentThread()
        time.sleep(1)
        events.remove(e)
        events[0].set()

for i in range(3):
    t = threading.Thread(target=f, args=(threading.Event(),))
    t.setDaemon(1)
    t.start()
while not events:
    print events
    time.sleep(0.1)
events[0].set()
time.sleep(10)

HTH,
Martin



More information about the Python-list mailing list