锁与信号量


目录

  1. 添加线程锁
  2. 锁的本质
  3. 互斥锁与可重入锁
  4. 死锁的产生
  5. 锁的上下文管理
  6. 信号量与有界信号量

 

添加线程锁

由于多线程对资源的抢占顺序不同,可能会产生冲突,通过添加线程锁来对共有资源进行控制。

 1 import atexit
 2 from random import randrange
 3 from threading import Thread, Lock, current_thread # or currentThread
 4 from time import ctime, sleep
 5 
 6 
 7 # Use set to record the running thread
 8 # If we print set directly, it will shows set([a, b, c])
 9 # So we reload the __str__ function to show it more clean(shows a, b, c as we want)
10 class CleanOutputSet(set):
11     def __str__(self):
12         return ', '.join(x for x in self)
13     
14 # randrange(2, 5) will generate a num in range(2, 5)
15 # for x in range(randrange(3, 7)) will do "for" loop 3-7 times
16 # Below code generate a list which contains 3-6 numbers in range 2-4
17 # If not list(), it will return a generator, and it will be null after one time iteration
18 loops = list((randrange(2, 5) for x in range(randrange(3, 7))))
19 
20 remaining = CleanOutputSet()
21 lock = Lock()
22 
23 def loop_without_lock(nsec):
24     myname = current_thread().name
25     remaining.add(myname)
26     print('[%s] Start %s' % (ctime(), myname))
27     sleep(nsec)
28     remaining.remove(myname)
29     print('[%s] Completed %s (%d secs)' % (ctime(), myname, nsec))
30     # Note: remaining or 'NONE', will return 'NONE' if remaining is Null
31     # Null including: None, False, (), [], {}, 0
32     print('    (remaining: %s)' % (remaining or 'NONE'))
33 
34 def loop_with_lock(nsec):
35     myname = current_thread().name
36     # When we need to modifiy public resource, acquire lock to block other threads
37     # Lock acquire and release can use 'with lock' to simplify
38     lock.acquire()
39     remaining.add(myname)
40     print('[%s] Start %s' % (ctime(), myname))
41     # After using resource, release lock for other threads to use
42     lock.release()
43     sleep(nsec)
44 
45     lock.acquire()
46     remaining.remove(myname)
47     print('[%s] Completed %s (%d secs)' % (ctime(), myname, nsec))
48     print('    (remaining: %s)' % (remaining or 'NONE'))
49     lock.release()
50     
51 def _main():
52     print('-----Below threads without lock-----')
53     threads = []
54     for pause in loops:
55         threads.append(Thread(target=loop_without_lock, args=(pause, )))
56     for t in threads:
57         t.start()
58     for t in threads:
59         t.join()
60     print('-----Below threads with lock-----')
61     threads = []
62     for pause in loops:
63         threads.append(Thread(target=loop_with_lock, args=(pause, )))
64     for t in threads:
65         t.start()
66     for t in threads:
67         t.join()
68 
69 # This is an exit function, when script exit, this function will be called
70 # You can use atexit.register(_atexit) to replace @atexit.register
71 # The function name '_atexit' can be change to others
72 @atexit.register
73 def _atexit():
74     print('All DONE at:', ctime())
75 
76 if __name__ == '__main__':
77     _main()

第 1-4 行,首先导入需要的模块,atexit用于设置退出脚本时的处理函数,random用于产生随机数来增加线程的不确定性。

第 7- 12 行,定义一个新的集合类,用于输出当前运行线程的集合,新的集合类CleanOutputSet重载了__str__方法,使集合的显示由set([a, b, c])变为我们想要的a, b, c形式。

 第 14-21行,利用随机数模块,产生一个生成器,包含3-6个大小在2-4之间的随机数,为了后续重复使用,此处对生成器进行list操作,否则生成器在迭代一次之后将变为空,无法复用。同时对全局锁和集合输出类进行实例化。

第 23-32 行,定义一个不加锁的线程函数,该函数会在进入时向集合添加线程名,sleep相应时间后,移除线程名,同时显示集合(共有资源)内剩余的线程名。

第 34-49 行,定义一个加锁的线程函数,该函数会在进入时获取线程锁,之后再向集合添加线程名,添加完成后释放线程锁,sleep相应时间后,获取线程锁,移除线程名,同时显示集合(共有资源)内剩余的线程名,最后释放线程锁。

第 51-67 行,主函数中分别对加锁和不加锁的两种线程方式进行调用,并利用join()方法挂起线程以区分开两种方式的运行。

第 69-77 行,利用atexit.register函数/@register装饰器定义脚本退出函数。

最后输出结果

-----Below threads without lock-----  
[Tue Aug  1 11:01:57 2017] Start Thread-1  
[Tue Aug  1 11:01:57 2017] Start Thread-2[Tue Aug  1 11:01:57 2017] Start Thread-3  
[Tue Aug  1 11:01:57 2017] Start Thread-4  
  
[Tue Aug  1 11:01:59 2017] Completed Thread-3 (2 secs)  
    (remaining: Thread-1, Thread-4, Thread-2)  
[Tue Aug  1 11:02:00 2017] Completed Thread-1 (3 secs)  
    (remaining: Thread-4, Thread-2)  
[Tue Aug  1 11:02:01 2017] Completed Thread-2 (4 secs)[Tue Aug  1 11:02:01 2017] Completed Thread-4 (4 secs)  
  
    (remaining: NONE)    (remaining: NONE)  
  
-----Below threads with lock-----  
[Tue Aug  1 11:02:01 2017] Start Thread-5  
[Tue Aug  1 11:02:01 2017] Start Thread-6  
[Tue Aug  1 11:02:01 2017] Start Thread-7  
[Tue Aug  1 11:02:01 2017] Start Thread-8  
[Tue Aug  1 11:02:03 2017] Completed Thread-7 (2 secs)  
    (remaining: Thread-8, Thread-6, Thread-5)  
[Tue Aug  1 11:02:04 2017] Completed Thread-5 (3 secs)  
    (remaining: Thread-8, Thread-6)  
[Tue Aug  1 11:02:05 2017] Completed Thread-6 (4 secs)  
    (remaining: Thread-8)  
[Tue Aug  1 11:02:05 2017] Completed Thread-8 (4 secs)  
    (remaining: NONE) 
View Code

相关文章:

  • 2022-01-09
  • 2022-12-23
  • 2022-12-23
  • 2021-08-14
  • 2021-09-08
  • 2021-09-21
  • 2021-07-16
猜你喜欢
  • 2021-09-25
  • 2021-09-07
  • 2022-12-23
  • 2021-05-13
  • 2022-12-23
  • 2022-01-24
  • 2022-12-23
相关资源
相似解决方案