Python-Threading-Module

threading.Lock()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
lock.acquire([wait]) 非可重入锁。
获得锁返回 True;反之 False
a)wait不设置,或者设置为 True,线程锁处在堵塞模式。
b)wait不设置,或者设置为 True,acquire一个处在unlocked状态的线程锁,将立即返回True:
lock = threading.Lock()
print lock.acquire()
>>>True
acquire一个处在 locked状态的线程锁,堵塞等待锁被释放。如果锁已经被调用线程获取,则导致死锁:
lock = threading.Lock()
print lock.acquire()
>>>True
lock.acquire() #deadlock
c)wait设置为 False,将处在非堵塞模式。
d)wait设置为 False, acquire一个处在unlocked状态的线程锁,将立即返回 True
lock = threading.lock()
print lock.acquire(False)
>>>True
print lock.acquire(False)
>>>False #不能获取锁,返回False(即使由已经持有锁的线程调用)
acquire一个处在locked状态的线程锁,将返回False。不会导致死锁。
( lock.acquire(False), 类似linux pthread库中的 trylock()函数。获取锁立即返回True,不能获取锁立即返回False )

总结

<table>
<tr>
     <td> wait参数</td> <td> lock处在unlocked状态 </td> <td> lock处在locked状态 </td>
</tr><tr>
    <td> 不设置或者 True </td><td> True </td> <td> 等待直到unlocked,返回True</td>
</tr><tr>
    <td> False </td><td> True </td> <td> 立即返回 False </td>
</tr>
</table>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
lock.release()
返回None; 或者raise thread.error
a) 可以被任意线程调用,即一个线程锁可以被持有改锁的线程释放,或者其他不持有该锁的线程释放
import threading
import time
def unlock(lock):
time.sleep(3)
lock.release()
print 'unlock in another thread'
lock = threading.Lock()
lock.acquire() #持有锁
release_in_another_thread = threading.Thread(target=unlock, args=[lock,]) #在其他线程调用release
release_in_another_thread.start()
print 'acquire the lock again: ', lock.acquire() #堵塞直到锁被释放,然后再次持有
#2个线程同时print,顺序是任意的。
>>>acquire the lock again: True
>>>unlock in another thread
b) release一个处在unlocked状态的线程锁,会引起 thread.error异常。
lock = threading.Lock()
lock.release()
>>>thread.error: release unlocked lock

threading.RLock(verbose=None) #可重入锁(reentrant lock),


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a)verbose=None,不打印调试信息
b)acquire和release必须调用次数相同,release不能由不持有锁的线程调用(RuntimeError)
rlock.acquire([wait])
立即返回,获得锁返回True;反之返回False;非第一次获得锁返回 1
a) 第一次获取锁返回True; 非第一次获取锁返回 1; 不能获取锁返回 False
b) 持有锁的线程重复调用acquire,wait默认、设置为True、或者设置为False 均立即返回。
c) 不持有锁的线程调用acquire,wait默认或者设置为True则堵塞;wait设置为False则立即返回 False
d) RLock可以反复获取多次,目前(2.7.5)没有上限(至少1024,估计受限于内存大小)。
rlock.release()
返回None;release非持有的锁raise RuntimeError;
a) 只能由持有锁的线程调用,否则raise RuntimeError。
b)释放一个unlocked的锁,raise RuntimeError 与Lock的情况不一致。

Lock和RLock的区别

  1. Lock能够由非持有锁的线程release,但是RLock不可以。
  2. Lock不能够重入(wait=True则死锁,wait=False则返回False), 但是RLock可以重入多次。
  3. Lock的acquire只返回 True 或者 False; Rlock重复获取锁时返回 1。
  4. 对一个unlocked状态的lock调用 release 引起thread.error异常; RLock 则引起RuntimeError异常。

threading.Condition([lock])


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
创建成功返回None; 失败返回AttributeEror(传入了错误的lock参数)
cv.acquire() --> lock.acquire()
直接调用低层的lock.acquire函数。因此其表现与具体的lock的类型相同。
a) 默认无参数调用,创建RLock
b) 传入threading.Lock(), 类型的lock
cv.release() --> lock.release()
直接调用低层的lock.release()函数。因此表现与具体的lock的类型相同。
a)默认参数调用,创建RLock, 如果release一个unlocked状态的锁,返回RuntimeError
b)传入threading.Lock, 如果release一个unlocked状态的锁,返回 error: release unlocked lock
c)由于RLock和Lock处理release的情况不同,因此返回也不同,具有不一致性。
cv.wait([timeout]) --> lock.wait()
直接调用低层的lock.wait函数。因此表现与具体的lock的类型相同
cv.notify_all == cv.notifyAll
后者在python3.0中被取消。(所有camelName在py3.0中都被转化为camel_name形式)

令人感兴趣的是,由于Lock与RLock的不同,那么传入一个Lock与使用一个RLock作为Condition的锁时, 其表现究竟如何。

threading.Semaphore(value=1)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
value默认值为1,即二元锁
threading.acquire(blocking=True)
获取信号量,并将信号值减少1
threading.release()
释放信号量,并将信号值加1
release函数会将信号值增加1。 Semaphore类不会记住信号值的初值(value),如果调用release的次数多于acquire,那么会导致信号值变大。
import threading
sem = threading.Semaphore(1)
sem.acquire(False)
>>>True
sem.acquire(False)
>>>False
sem.relase()
sem.release() #多调用的release导致下面能acquire两次。
sem.acquire(False)
>>>True
sem.acquire(False)
>>>True

threading.Event


1
2
3
4
5
6
>Event本质上就是一个二元信号量
* e.is_set() 检查事件是否发生
* e.set() 设置事件发生
* e.clear() 清除事件
* e.wait([timeout]) 等待事件发生(e.set被调用)或者超时