Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread condition variables: un-acquired lock

I have this example in Python which demonstrates the use of condition variables.

import logging
import threading
import time

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s (%(threadName)-2s) %(message)s',)

def consumer(cond):

    # wait for the condition and use the resource

    logging.debug('Starting consumer thread')

    t = threading.currentThread()

    cond.wait()

    logging.debug('Resource is available to consumer')

def producer(cond):

    # set up the resource to be used by the consumer

    logging.debug('Starting producer thread')

    logging.debug('Making resource available')

    cond.notifyAll()


condition = threading.Condition()

# pass each thread a 'condition'
c1 = threading.Thread(name='c1', target=consumer, args=(condition,))
c2 = threading.Thread(name='c2', target=consumer, args=(condition,))
p = threading.Thread(name='p', target=producer, args=(condition,))


# start two threads and put them into 'wait' state
c1.start()
c2.start()

# after two seconds or after some operation notify them to free or step over the wait() function
time.sleep(2)
p.start()

However, it raises a runtime error un-acquired lock on threads. I have an idea that I need to use acquire and release functions but I'm not sure about their usage and what exactly they do.

like image 718
cpx Avatar asked Apr 16 '14 17:04

cpx


People also ask

What is a lock and condition variable?

A collection of procedures manipulating a shared data structure. One lock that must be held whenever accessing the shared data (typically each procedure acquires the lock at the very beginning and releases the lock before returning). One or more condition variables used for waiting.

Why do I need condition variables can't I just use mutex locks for all synchronization problems?

A mutex might have several related condition variables. And you need condition variables because such conditions may not always be expressed as simply as "a mutex is locked" (so you need to broadcast changes in conditions to other threads).

What is thread condition?

A condition variable allows one or more threads to wait until they are notified by another thread. If the lock argument is given and not None , it must be a Lock or RLock object, and it is used as the underlying lock. Otherwise, a new RLock object is created and used as the underlying lock.

Why do condition variables need mutex?

Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.


1 Answers

Conditions are a wrapper around an underlying Lock that provide wait/notify functionality. You need to acquire a lock before you can release it - which wait does under the hood. Notably once it gets re-awoken, it reacquires the lock. Thus mutual exclusion is ensured between acquiring and releasing, with wait "yielding" control of the lock, if that makes sense.

Instead of doing the acquiring/releasing manually, just use the Condition as a context manager:

def consumer(cond):
    with cond:
        cond.wait()

    logging.debug('Resource is available to consumer')

If for whatever reason you're stuck on a version of python without context managers, this is equivalent to:

def consumer(cond):
    try:
        cond.acquire()
        cond.wait()
    finally:
        cond.release()

    logging.debug('Resource is available to consumer')

Often you want to make sure that only one consumer gets awoken, so the following idiom is frequently used:

with cond:
    while some_queue.isEmpty():
        cond.wait()
    #get one from queue

Thus you could notify any number of consumers and the extra ones just go immediately back to sleep once the Queue is empty.

like image 119
roippi Avatar answered Sep 28 '22 22:09

roippi