Putting a thread to sleep until event X occurs

10,219

Solution 1

What you're looking for is known as a condition variable.

Condition Variables

Here is the Python 2 library reference.
For Python 3 it can be found here

Solution 2

Looks like you want a threading.Semaphore associated with each handler (other synchronization objects like Events and Conditions are also possible, but a Semaphore seems simplest for your needs). (Specifically, use a BoundedSemaphore: for your use case, that will raise an exception immediately for programming errors that erroneously release the semaphone more times than they acquire it -- and that's exactly the reason for being of the bounded version of semaphones;-).

Initialize each semaphore to a value of 1 when you build it (so that means the handler is available). Each using-thread calls acquire on the semaphore to get the handler (that may block it), and release on it when it's done with the handler (that will unblock exactly one of the waiting threads). That's simpler than the acquire/wait/notify/release lifecycle of a Condition, and more future-proof too, since as the docs for Condition say:

The current implementation wakes up exactly one thread, if any are waiting. However, it’s not safe to rely on this behavior. A future, optimized implementation may occasionally wake up more than one thread.

while with a Semaphore you're playing it safe (the semantics whereof are safe to rely on: if a semaphore is initialized to N, there are at all times between 0 and N-1 [[included]] threads that have successfully acquired the semaphore and not yet released it).

Share:
10,219

Related videos on Youtube

tipu
Author by

tipu

code n stuff

Updated on May 25, 2022

Comments

  • tipu
    tipu almost 2 years

    I'm writing to many files in a threaded app and I'm creating one handler per file. I have HandlerFactory class that manages the distribution of these handlers. What I'd like to do is that

    thread A requests and gets foo.txt's file handle from the HandlerFactory class

    thread B requests foo.txt's file handler

    handler class recognizes that this file handle has been checked out

    handler class puts thread A to sleep

    thread B closes file handle using a wrapper method from HandlerFactory

    HandlerFactory notifies sleeping threads

    thread B wakes and successfully gets foo.txt's file handle

    This is what I have so far,

    def get_handler(self, file_path, type):
        self.lock.acquire()
        if file_path not in self.handlers:
            self.handlers[file_path] = open(file_path, type)
        elif not self.handlers[file_path].closed:
            time.sleep(1)
        self.lock.release()
        return self.handlers[file_path][type]
    

    I believe this covers the sleeping and handler retrieval successfully, but I am unsure how to wake up all threads, or even better wake up a specific thread.

  • Mark Amery
    Mark Amery almost 9 years
    The GIL does not significantly degrade I/O performance, only processing performance (see wiki.python.org/moin/GlobalInterpreterLock). Since the OP seems to be using threads to parallelise I/O, your assertion that he is losing most of the benefits of multi-threading is unwarranted.
  • Ami
    Ami almost 9 years
    I suggest you look at page 38 of the referenced PDF file at dabeaz.com/python/GIL.pdf. Even with 1 CPU the GIL degrades response time of I/O bound threads on a multi-core system (and sometimes on a single-core system), if you are using multiple python threads, due to the overhead of checking the GIL.