线程同步(线程锁)

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)但是当线程需要共享数据时,可能存在数据不同步的问题。为了避免这种情况,引入了锁的概念。
1 lock = threading.Lock()
2 lock.acquire()  # 请求得到锁
3 lock.release()  # 释放锁
4 只要不释放其他的线程都无法进入运行状态

 

1、初始程序:

import threading
import random
import time

lock = threading.Lock()

list1 = [0] * 10  # [0,0,0,0,0,0,0,0,0,0]


def task1():
    for i in range(len(list1)):
        list1[i] = 1    # random.randint(1, 100)
        time.sleep(0.5)
        print(list1)


def task2():
    for i in range(len(list1)):
        print(f'当前的值是{i}')
        time.sleep(0.5)


if __name__ == '__main__':
    t1 = threading.Thread(target=task1)
    t2 = threading.Thread(target=task2)

    t1.start()
    t2.start()

运行结果:

当前的值是0
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
当前的值是1
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
当前的值是2
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
当前的值是3
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
当前的值是4
[1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
当前的值是5
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
当前的值是6
[1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
当前的值是7
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
当前的值是8
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
当前的值是9
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

进程已结束,退出代码0

 

 

2、程序加锁:

 1 import threading
 2 import random
 3 import time
 4 
 5 lock = threading.Lock()
 6 
 7 list1 = [0] * 10  # [0,0,0,0,0,0,0,0,0,0]
 8 
 9 
10 def task1():
11     lock.acquire()    # 请求得到锁
12     for i in range(len(list1)):
13         list1[i] = 1    # random.randint(1, 100)
14         time.sleep(0.5)
15         print(list1)
16     lock.release()    # 释放锁
17 
18 
19 def task2():
20     # 获取线程锁,如果已经上锁,则等待锁的释放
21     lock.acquire()
22     for i in range(len(list1)):
23         print(f'当前的值是{i}')
24         time.sleep(0.5)
25     lock.release()
26 
27 
28 if __name__ == '__main__':
29     t1 = threading.Thread(target=task1)
30     t2 = threading.Thread(target=task2)
31 
32     t1.start()
33     t2.start()

运行结果:

[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
[1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
[1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
当前的值是0
当前的值是1
当前的值是2
当前的值是3
当前的值是4
当前的值是5
当前的值是6
当前的值是7
当前的值是8
当前的值是9

进程已结束,退出代码0

 

死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。尽管死锁很少发生,但一旦发生就会造成应用的停止响应,程序不做任何事情。
 
为什么会产生死锁?
1.因为系统资源不足。
2.进程运行推进的顺序不合适。   
3.资源分配不当
 
例如:     
死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况。
 
死锁案例:
 1 from threading import Thread, Lock
 2 import time
 3 
 4 lockA = Lock()
 5 lockB = Lock()
 6 
 7 
 8 class MyThread1(Thread):    # 自定义线程
 9     def run(self):
10         if lockA.acquire():
11             print(f"{self.name}获取了A锁....")
12             time.sleep(0.1)
13 
14             if lockB.acquire(timeout=5):    # 超时自动释放锁,自动调用 release()
15                 print(f"{self.name}又获取了B锁,原程序中还有A锁")
16                 lockB.release()
17 
18             lockA.release()
19 
20 
21 class MyThread2(Thread):
22     def run(self):
23         if lockB.acquire():
24             print(f"{self.name}获取了B锁....")
25             time.sleep(0.1)
26 
27             if lockA.acquire(timeout=5):    # 超时自动释放锁,自动调用 release()
28                 print(f"{self.name}又获取了A锁,原程序中还有B锁")
29                 lockA.release()
30 
31             lockB.release()
32 
33 
34 if __name__ == '__main__':
35     t1 = MyThread1()
36     t2 = MyThread2()
37 
38     t1.start()
39     t2.start()

原运行结果:

解决死锁后的运行结果:

Thread-1获取了A锁....
Thread-2获取了B锁....
Thread-1又获取了B锁,原程序中还有A锁

进程已结束,退出代码0
 
产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
只要破坏了一个必要条件,那么我们的死锁就解决了
posted @ 2022-09-24 17:09  DUDU-  阅读(29)  评论(0编辑  收藏  举报