临界资源即那些一次只能被一个线程访问的资源,典型例子就是打印机,它一次只能被一个程序用来执行打印功能,因为不能多个线程同时操作,而访问这部分资源的代码通常称之为临界区。
锁机制
threading的Lock类,用该类的acquire函数进行加锁,用realease函数进行解锁
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
|
import threading import time class Num: def __init__( self ): self .num = 0 self .lock = threading.Lock() def add( self ): self .lock.acquire() #加锁,锁住相应的资源 self .num + = 1 num = self .num self .lock.release() #解锁,离开该资源 return num n = Num() class jdThread(threading.Thread): def __init__( self ,item): threading.Thread.__init__( self ) self .item = item def run( self ): time.sleep( 2 ) value = n.add() #将num加1,并输出原来的数据和+1之后的数据 print ( self .item,value) for item in range ( 5 ): t = jdThread(item) t.start() t.join() #使线程一个一个执行 |
当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”(参见多线程的基本概念)。
直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
信号量
信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用了release方法将内部计数器更新到大于1位置。
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
29
|
import threading import time class Num: def __init__( self ): self .num = 0 self .sem = threading.Semaphore(value = 3 ) #允许最多三个线程同时访问资源 def add( self ): self .sem.acquire() #内部计数器减1 self .num + = 1 num = self .num self .sem.release() #内部计数器加1 return num n = Num() class jdThread(threading.Thread): def __init__( self ,item): threading.Thread.__init__( self ) self .item = item def run( self ): time.sleep( 2 ) value = n.add() print ( self .item,value) for item in range ( 100 ): t = jdThread(item) t.start() t.join() |
条件判断
所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。
它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
""" 一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1. """ """ 使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有 wait, notify, notifyAll 方法。 """ import threading import queue,time,random class Goods: #产品类 def __init__( self ): self .count = 0 def add( self ,num = 1 ): self .count + = num def sub( self ): if self .count> = 0 : self .count - = 1 def empty( self ): return self .count < = 0 class Producer(threading.Thread): #生产者类 def __init__( self ,condition,goods,sleeptime = 1 ): #sleeptime=1 threading.Thread.__init__( self ) self .cond = condition self .goods = goods self .sleeptime = sleeptime def run( self ): cond = self .cond goods = self .goods while True : cond.acquire() #锁住资源 goods.add() print ( "产品数量:" ,goods.count, "生产者线程" ) cond.notifyAll() #唤醒所有等待的线程--》其实就是唤醒消费者进程 cond.release() #解锁资源 time.sleep( self .sleeptime) class Consumer(threading.Thread): #消费者类 def __init__( self ,condition,goods,sleeptime = 2 ): #sleeptime=2 threading.Thread.__init__( self ) self .cond = condition self .goods = goods self .sleeptime = sleeptime def run( self ): cond = self .cond goods = self .goods while True : time.sleep( self .sleeptime) cond.acquire() #锁住资源 while goods.empty(): #如无产品则让线程等待 cond.wait() goods.sub() print ( "产品数量:" ,goods.count, "消费者线程" ) cond.release() #解锁资源 g = Goods() c = threading.Condition() pro = Producer(c,g) pro.start() con = Consumer(c,g) con.start() |
同步队列
put方法和task_done方法,queue有一个未完成任务数量num,put依次num+1,task依次num-1.任务都完成时任务结束。
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
29
30
31
32
33
34
35
36
37
38
|
import threading import queue import time import random ''' 1.创建一个 Queue.Queue() 的实例,然后使用数据对它进行填充。 2.将经过填充数据的实例传递给线程类,后者是通过继承 threading.Thread 的方式创建的。 3.每次从队列中取出一个项目,并使用该线程中的数据和 run 方法以执行相应的工作。 4.在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号。 5.对队列执行 join 操作,实际上意味着等到队列为空,再退出主程序。 ''' class jdThread(threading.Thread): def __init__( self ,index,queue): threading.Thread.__init__( self ) self .index = index self .queue = queue def run( self ): while True : time.sleep( 1 ) item = self .queue.get() if item is None : break print ( "序号:" , self .index, "任务" ,item, "完成" ) self .queue.task_done() #task_done方法使得未完成的任务数量-1 q = queue.Queue( 0 ) ''' 初始化函数接受一个数字来作为该队列的容量,如果传递的是 一个小于等于0的数,那么默认会认为该队列的容量是无限的. ''' for i in range ( 2 ): jdThread(i,q).start() #两个线程同时完成任务 for i in range ( 10 ): q.put(i) #put方法使得未完成的任务数量+1 |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/sunhuaqiang1/article/details/69389316