Python多线程 threading模块[4] Lock互斥锁

       前面已经演示了《Python多线程 threading 模块 两种方式启动线程》《Python多线程 threading 模块 Thread类的重要函数》,这两篇文章的示例都是演示了互不相干的独立线程,现在我们考虑这样一个问题:假设各个线程需要访问同一公共资源,我们的代码该怎么写?

# !/usr/bin/python3
# coding: utf-8
import threading
import time

counter = 0


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global counter
        time.sleep(1);
        counter += 1
        print("Name: %s, Counter: %s" % (self.name, counter))


if __name__ == "__main__":
    for i in range(0, 10):
        my_thread = MyThread()
        my_thread.start()

        解决上面的问题,我们兴许会写出这样的代码,我们假设跑10个线程,但是这10个线程都会去访问counter这个公共资源,并对该资源进行处理(counter += 1),代码看起来就是这个样了,但是我们看下运行结果:

Name: Thread-2, Counter: 1
Name: Thread-6, Counter: 2
Name: Thread-3, Counter: 3
Name: Thread-7, Counter: 4
Name: Thread-10, Counter: 5
Name: Thread-1, Counter: 6
Name: Thread-5, Counter: 7
Name: Thread-9, Counter: 8
Name: Thread-4, Counter: 9
Name: Thread-8, Counter: 10

       从中我们已经看出了这个全局资源(counter)被抢占的情况,问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。在开发过程中我们必须要避免这种情况,那怎么避免?这就用到了我们在综述中提到的互斥锁了。

 

互斥锁

        Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。

        我们对上面的程序进行整改,为此我们需要添加一个互斥锁变量mutex = threading.Lock(),然后在争夺资源的时候之前我们会先抢占这把锁mutex.acquire(),对资源使用完成之后我们在释放这把锁mutex.release()。代码如下:

# !/usr/bin/python3
# coding: utf-8
import threading
import time

counter = 0
mutex = threading.Lock()


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global counter, mutex
        time.sleep(1)
        if mutex.acquire():
            counter += 1
            print("Name: %s, Counter: %s" % (self.name, counter))
            mutex.release()


if __name__ == "__main__":
    for i in range(0, 10):
        my_thread = MyThread()
        my_thread.start()

 

同步阻塞

        当一个线程调用Lock对象的acquire()方法获得锁时,这把锁就进入“locked”状态。因为每次只有一个线程1可以获得锁,所以如果此时另一个线程2试图获得这个锁,该线程2就会变为“blo同步阻塞状态。直到拥有锁的线程1调用锁的release()方法释放锁之后,该锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

 

进一步考虑

通过对公共资源使用互斥锁,这样就简单的到达了我们的目的,但是如果我们又遇到下面的情况:

        1、遇到锁嵌套的情况该怎么办,这个嵌套是指当我一个线程在获取临界资源时,又需要再次获取

        2、如果有多个公共资源,在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源

上述这两种情况会直接造成程序挂起,即死锁,下面我们会谈死锁及可重入锁RLock。

 

相关阅读

《Python多线程 threading模块[1] 概述》

《Python多线程 threading模块[2] 两种方式启动线程》

《Python多线程 threading模块[3] Thread类的重要函数》

《Python多线程 threading模块[4] Lock互斥锁》

《Python多线程 threading模块[5] 死锁的形成》

《Python多线程 threading模块[6] 可重入锁RLock》

《Python多线程 threading模块[7] Event线程通信》

《Python多线程 threading模块[8] Condition实现复杂同步》

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值