随笔 - 208  文章 - 0 评论 - 0 阅读 - 30770
< 2025年1月 >
29 30 31 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 1
2 3 4 5 6 7 8

线程锁

多线程修改数据会造成混乱

from threading import Thread
import time
x = 0

def task():
    global x
    for i in range(100000): # 最少10万级别才能看出来
        x = x+1   # 有可能右边的x刚拿到了0,
        # 发生线程不安全的原因:
        # t1 x+1 阶段 x = 0 保存了状态 cpu被切走  t2 x+1 x = 0 保存了状态 cpu被切走
        # 下次t1 继续运行代码 x = 0+1  下次t2 再运行代码的时候也是 x = 0+1
        #  也就说修改了两次 x 只加了一次1 。
        # time.sleep()
    # lock.release()
if __name__ == '__main__':
    t_list = []
    for i in range(3):
        t = Thread(target=task)
        t_list.append(t)
        t.start()
    for i in t_list:
        i.join()

    print(x)

使用线程锁解决线程修改数据混乱问题

from threading import Thread,Lock
x=0
mutex=Lock()
def task():
    global x
    mutex.acquire()
    for i in range(200000):
        x=x+1
    mutex.release()

if __name__ == '__main__':
    t_list=[]
    for i in range(3):
        t=Thread(target=task)
        t_list.append(t)
        t.start()
    for i in t_list:
        i.join()
    print(x)

死锁问题

from threading import Thread,Lock
mutex1=Lock()
mutex2=Lock()
import time
class MyThread(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name}抢到了 锁1')
        mutex2.acquire()
        print(f'{self.name}抢到了 锁2')
        mutex2.release()
        print(f'{self.name}释放了 锁2')
        mutex1.release()
        print(f'{self.name}释放了 锁1')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name}抢到了 锁2')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name}抢到了 锁1')
        mutex1.release()
        print(f'{self.name}释放了 锁1')
        mutex2.release()
        print(f'{self.name}释放了 锁2')

for i in range(3):
    t=MyThread()
    t.start()
    
    
# 两个线程
# 线程1拿到了(锁头2)想要往下执行需要(锁头1),
# 线程2拿到了(锁头1)想要往下执行需要(锁头2)
# 互相都拿到了彼此想要往下执行的必需条件,互相都不放手里的锁头.

死锁问题解决方法

解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:

from threading import Thread,RLock
# 递归锁 在同一个线程内可以被多次acquire
# 如何释放 内部相当于维护了一个计数器 也就是说同一个线程 acquire了几次就要release几次
mutex1=RLock()
mutex2=mutex1
import time
class MyThread(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name}抢到了 锁1')
        mutex2.acquire()
        print(f'{self.name}抢到了 锁2')
        mutex2.release()
        print(f'{self.name}释放了 锁2')
        mutex1.release()
        print(f'{self.name}释放了 锁1')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name}抢到了 锁2')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name}抢到了 锁1')
        mutex1.release()
        print(f'{self.name}释放了 锁1')
        mutex2.release()
        print(f'{self.name}释放了 锁2')

for i in range(3):
    t=MyThread()
    t.start()
posted on   黑糖A  阅读(140)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 上周热点回顾(1.20-1.26)
点击右上角即可分享
微信分享提示