Address #189 ensuring socket locks are released
The code previous assume exception-free execution of critical blocks
between lock acquire() and lock release(); however, in Python exceptions
can be thrown in many situations which would then result in a dead-lock
of the entire program using pigpio.
This is resolved by using the acquire/try/finally/release pattern to
ensure that the lock is always released, even when an exception occurs.
Also addresses #186, but takes a slightly different approach by using
RLock to handle the nested lock requirement, which overall should be
safer because it handles additional situations that can cause a
deadlock.