3. Synchronization

You typically do not need to use synchronization primitives with Shrapnel because coroutines are cooperative. However, there are situations where they can be useful. For example, if you manipulate multiple shared data structures that need to remain consistent, and you have potentially context-switch calls interspersed (such as socket I/O).

3.1. Synchronization Classes

class coro.condition_variable

Bases: object

condition_variable()

This locking primitive provides a method to “trigger” an event for other threads.

Variables:_waiting – A fifo of coroutine objects waiting for the lock. (C only.)
raise_all(self, the_exception)

Raise an exception on all waiting threads.

Parameters:the_exception – The exception to raise on all waiting threads.
wait(self)

Wait for the condition variable to be triggered.

Returns:The arguments given to the wake call (defaults to the empty tuple).
wait_timeout(self, timeout)

Deprecated.

wake_all(self, args=())

Wake all waiting threads.

Parameters:args – The arguments to wake the thread with. Defaults to the empty tuple.
wake_n(self, int count, args=())

Wake a specific number of threads.

Parameters:
  • count – The number of threads to wake up.
  • args – The arguments to wake the thread with. Defaults to the empty tuple.
Returns:

The total number of threads actually awoken.

wake_one(self, args=())

Wake only 1 thread.

If there are no threads waiting, this does nothing.

Parameters:args – The arguments to wake the thread with. Defaults to the empty tuple.
Returns:True if a thread was awoken, False if not.
class coro.fifo

Bases: object

fifo()

First-in First-Out container.

This uses a linked list.

Variables:
  • fifo – The fifo object. (C only.)
  • cv – A condition variable. (C only.)
pop(self)

Pop an object from the head of the FIFO.

This blocks if the FIFO is empty.

Returns:The next object from the FIFO.
pop_all(self)

Pop all objects from the FIFO.

This will block if the fifo is empty and wait until there is an element to pop.

Returns:A list of objects. Returns an empty list if the FIFO is empty.
push(self, thing)

Push an object to the end of the FIFO.

Parameters:thing – The thing to add to the FIFO.
class coro.inverted_semaphore

Bases: object

inverted_semaphore(value=0)

An inverted semaphore works very much like a regular semaphore, except threads block _until_ the value reaches zero. For example, if you want a thread to wait for 1 or more events to finish, you can have each event raise the value (always nonblocking) and have your waiter thread call block_till_zero.

Parameters:

value – The value to start the semaphore with. It defaults to 0.

Variables:
  • value – The value of the inverted semaphore. Also available via __int__.
  • _waiting – A fifo of coroutine objects waiting for the semaphore to reach zero. (C only).
acquire(self, value=1)

Acquire a number of resource elements.

This never blocks.

Parameters:value – The number of resource elements to acquire (add to the semaphore). Defaults to 1.
block_till_zero(self)

Block until the inverted semaphore reaches zero.

This will return immediately if the value is already zero.

release(self, value=1)

Release a number of resource elements.

This never blocks. This may wake up waiting threads.

Parameters:value – The number of resource elements to release (subtract from the semaphore). Defaults to 1.
value

value: object

class coro.LockError

Bases: exceptions.Exception

class coro.mutex

Bases: object

mutex()

Mutual Exclusion lock object.

A single thread may acquire the mutex multiple times, but it must release the lock an equal number of times.

Variables:
  • _locked – Count of how many locks on the mutex are currently held.
  • _owner – The coroutine object that owns the lock (None if no owner). (C only.)
  • _waiting – A fifo of coroutine objects waiting for the lock.
has_lock(self, thread=None)

Determine if a particular coroutine has the lock.

Parameters:thread – The coroutine object to check if it owns the lock. If not specified, defaults to the current thread.
Returns:True if the specified thread has the lock, otherwise returns False.
lock(self)

Lock the mutex.

This will block if another coro already owns the mutex.

A coro thread may lock the mutex multiple times. It must call unlock the same number of times to release it.

Returns:True if it blocked, False if the mutex was acquired immediately.
locked(self)

Determine if the mutex is currently locked.

Returns:True if the mutex is locked, otherwise False.
trylock(self)

Try to lock the mutex.

Returns:True if it is already locked by another coroutine thread. Returns False if the lock was successfully acquired.
unlock(self)

Unlock the mutex.

The thread unlocking must be the thread that initially locked it.

Returns:True if another thread was waiting for the lock, otherwise it returns False.
class coro.semaphore

Bases: object

semaphore(value)

A semaphore is a locking primitive that corresponds with a set of resources. A semphore is essentially a counter. Whenever a resource is aquired, the count is lowered. If the count goes below 0, then it blocks until it goes above zero. Once you are done with a resource, you raise the counter.

Parameters:

value – The value to start the semaphore with (an integer).

Variables:
  • avail – The current value of the semaphore. Also available via __int__.
  • _waiting – A fifo of (value, co) tuples of coroutines waiting for the semaphore. value is the value being requested, and co is the coroutine object. (C only.)
acquire(self, int value)

Acquire a number of resource elements from the semaphore.

This will subtract the given value from the semaphore. This will block if the requested number of resource elements are not available (if the value would go negative).

Parameters:value – The number of resource elements.
avail

avail: object

release(self, int value)

Release a number of resource elements.

Parameters:value – The number of resource elements to release (add to the sempahore).

Table Of Contents

This Page