Python线程指南(下)

3.2. Lock

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

构造方法: 
Lock()

实例方法: 
acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。 
release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

01 # encoding: UTF-8
02 import threading
03 import time
04  
05 data = 
06 lock = threading.Lock()
07  
08 def func():
09     global data
10     print '%s acquire lock...' % threading.currentThread().getName()
11     
12     # 调用acquire([timeout])时,线程将一直阻塞,
13     # 直到获得锁定或者直到timeout秒后(timeout参数可选)。
14     # 返回是否获得锁。
15     if lock.acquire():
16         print '%s get the lock.' % threading.currentThread().getName()
17         data += 1
18         time.sleep(2)
19         print '%s release lock...' % threading.currentThread().getName()
20         
21         # 调用release()将释放锁。
22         lock.release()
23  
24 t1 = threading.Thread(target=func)
25 t2 = threading.Thread(target=func)
26 t3 = threading.Thread(target=func)
27 t1.start()
28 t2.start()
29 t3.start()

3.3. RLock

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

构造方法: 
RLock()

实例方法: 
acquire([timeout])/release(): 跟Lock差不多。

01 # encoding: UTF-8
02 import threading
03 import time
04  
05 rlock = threading.RLock()
06  
07 def func():
08     # 第一次请求锁定
09     print '%s acquire lock...' % threading.currentThread().getName()
10     if rlock.acquire():
11         print '%s get the lock.' % threading.currentThread().getName()
12         time.sleep(2)
13         
14         # 第二次请求锁定
15         print '%s acquire lock again...' % threading.currentThread().getName()
16         if rlock.acquire():
17             print '%s get the lock.' % threading.currentThread().getName()
18             time.sleep(2)
19         
20         # 第一次释放锁
21         print '%s release lock...' % threading.currentThread().getName()
22         rlock.release()
23         time.sleep(2)
24         
25         # 第二次释放锁
26         print '%s release lock...' % threading.currentThread().getName()
27         rlock.release()
28  
29 t1 = threading.Thread(target=func)
30 t2 = threading.Thread(target=func)
31 t3 = threading.Thread(target=func)
32 t1.start()
33 t2.start()
34 t3.start()

3.4. Condition

Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于状态图中的等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

构造方法: 
Condition([lock/rlock])

实例方法: 
acquire([timeout])/release(): 调用关联的锁的相应方法。 
wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。 
notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。 
notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

例子是很常见的生产者/消费者模式:

view source print ?
01 # encoding: UTF-8
02 import threading
03 import time
04  
05 # 商品
06 product = None
07 # 条件变量
08 con = threading.Condition()
09  
10 # 生产者方法
11 def produce():
12     global product
13     
14     if con.acquire():
15         while True:
16             if product is None:
17                 print 'produce...'
18                 product = 'anything'
19                 
20                 # 通知消费者,商品已经生产
21                 con.notify()
22             
23             # 等待通知
24             con.wait()
25             time.sleep(2)
26  
27 # 消费者方法
28 def consume():
29     global product
30     
31     if con.acquire():
32         while True:
33             if product is not None:
34                 print 'consume...'
35                 product = None
36                 
37                 # 通知生产者,商品已经没了
38                 con.notify()
39             
40             # 等待通知
41             con.wait()
42             time.sleep(2)
43  
44 t1 = threading.Thread(target=produce)
45 t2 = threading.Thread(target=consume)
46 t2.start()
47 t1.start()

你可能感兴趣的:(Python线程指南(下))