Safely lock certain resources on incoming signals without blowing up memory.
If a block has a non-thread safe operation like opening a connection to a port, it is useful to place a Python
Lock object in your block to make sure that two, asynchronous signals do not trigger the operation at the same time.
However, sometimes this can cause blocking and memory to fill up the call stack queue if an operation will never complete or is taking longer than the incoming signal rate. The LimitLock mixin provides a method,
execute_with_lock that locks a method call across threads but only allows a certain number of callers to wait for the lock to free.
Include the mixin in your block's inheritance and call the
execute_with_lock method around the code you wish to lock
from nio import Block from nio.block.mixins import LimitLock class MyBlock(LimitLock, Block): def listen_on_port(self, port_no): # do something here like open a port def process_signal(self, signal): self.execute_with_lock(self.listen_on_port, 5, 5000)
This example has a method that opens a port, something only one thread can do at a time. If more than 5 threads try to grab the lock then a warning will be logged and an exception will be thrown.
Call a method once a lock frees but don't allow more than a certain number of threads to try to grab the lock. This method will block until the lock is acquired.
def execute_with_lock(self, execute_method, max_locks, *args, **kwargs)
- execute_method - The method to execute once the lock has been acquired
- max_locks - int - The maximum number of threads allowed to wait for a lock at a time
- args/*kwargs - additional arguments that will get passed to the execute method
Returns: The result of execute_method once it has run
LockQueueFull if there are too many threads trying to acquire the lock