threading中的锁

  • threading.Lock

  这个锁是不被某个特定线程所拥有的。一个线程获取了锁,之后任何线程尝试着获取锁,都会失败,包括这个获取了锁的线程自己尝试获取锁。

  例如,如下代码就会堵塞

import threading
lock = threading.Lock()
lock.acquire()
lock.acquire()
lock.release()
lock.release()

  lock.acquire(blocking=True, timeout=-1),返回的为True或者False,分别代表成功和失败。

  默认有两个参数,一个是blocking=True,意思是调用方法的时候没有获取到锁,就会堵塞线程,直到获取到锁为止。

import threading
lock = threading.Lock()
print(lock.acquire(blocking=True))
print(lock.acquire(blocking=False))

# output:
# True
# False

  另一个参数是timeout=-1,表示等待获取锁的时间,-1表示一直等待。如果超过timeout设定的时间还没有获取到锁就会有获取锁失败

import threading
lock = threading.Lock()
print(lock.acquire(blocking=True))
print(lock.acquire(timeout=1))

# output:
# True
# False

  这两个参数设定的时候需要注意,如何设定了timeout为正数,则不能设定blocking=False。因为设定了timeout为正数表明等待设定的时间会阻塞线程,和blocking=False是矛盾的。

  •  threading.RLock

  这个锁可以由同一个线程获取多次,它由除了locked和unlocked状态之外的owning thread和recursion level的概念组成。从一个已经获取了锁的线程中获取锁,需要调用acquire方法,如果该线程已经有锁,那么立刻返回True。如果需要释放锁,则调用release方法。

  注意,acquire()/release()方法成对出现,只有最后一个release()方法才会真正的释放该线程的锁,允许其他线程获取。

  参数和threading.Lock一样。。。

示例:该程序不会一直堵塞

import threading
lock = threading.RLock()
print(lock.acquire())
print(lock.acquire())
lock.release()
lock.release()

# output:
# True
# True
  • threading.Condition

  threading.Condition拥有比Lock和RLock更加细腻度的控制。该对象除了拥有acquire和release方法外还有如下方法:(下面三个方法在没有调用acquire之后和调用release之前是不能调用的)

  • wait交出线程的锁
  • notify通知其他线程条件发生变化,但是并不交出锁
  • notify_all如果有很多线程,那么使用notify_all

我觉得Condition中的线程主要有三种状态

  1. 运行状态:该线程获得控制权,正在运行
  2. 阻塞状态:该线程不可能获得控制权,相当于调用了wait方法,但是没有获得notify通知的线程
  3. 就绪状态:等待获得控制权的线程,该线程获得控制权就可以运行,获得了notify或者notify_all通知的线程

示例:生产者卖火锅丸子,总共生产10个。每生产五个,消费者才能开始吃。消费者吃完了之后,等待生产者生产丸子。

import threading
import time

class Producer(threading.Thread):
    def __init__(self, con):
        self.con = con
        super().__init__()

    def run(self):
        # times = 0
        global num
        self.con.acquire()
        for _ in range(10):
            print("开始添加丸子")
            num += 1
            print("火锅里面丸子的个数为:{}".format(num))
            time.sleep(1)
            if num == 5:
                print("火锅里面的丸子已经到达五个, 无法继续添加了")
                self.con.notify()
                self.con.wait()
            # times += 1
        self.con.release()

class Consumer(threading.Thread):
    def __init__(self, con):
        self.con = con
        super().__init__()

    def run(self):
        self.con.acquire()
        global num
        while num:
            print("开始吃啦!")
            num -= 1
            print("火锅里面的丸子剩余:{}".format(num))
            time.sleep(0.5)
            if num == 0:
                print("火锅里面没有丸子了,快点添加")
                self.con.notify()
                self.con.wait(6)
        self.con.release()
con = threading.Condition()
num = 0
p = Producer(con)
c = Consumer(con)
p.start()
c.start()

 

在 Python 中,`threading` 模块提供了 `Lock` 类来实现互斥机制,以确保多线程环境下共享资源的访问安全[^2]。互斥的基本原理是:当某个线程需要访问共享资源时,必须先获取;如果已经被其他线程占用,则当前线程会阻塞,直到被释放。这种机制可以有效防止多个线程同时修改共享资源导致的数据不一致问题。 ### 互斥的实现方法 1. **创建互斥** 使用 `threading.Lock()` 创建一个互斥对象。 ```python import threading mutex = threading.Lock() ``` 2. **获取** 线程在访问共享资源之前需要调用 `acquire()` 方法来获取。如果已经被其他线程占用,调用 `acquire()` 的线程将阻塞,直到被释放。 ```python mutex.acquire() ``` 3. **释放** 线程在完成对共享资源的操作后,必须调用 `release()` 方法释放,以便其他线程可以获取该并访问资源。 ```python mutex.release() ``` ### 示例代码 以下是一个使用互斥保护共享资源的示例代码: ```python 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(f"I am {self.name}, set counter: {counter}") mutex.release() if __name__ == "__main__": threads = [] for i in range(0, 100): my_thread = MyThread() my_thread.start() threads.append(my_thread) for thread in threads: thread.join() ``` 在这个示例中,`counter` 是一个共享资源,多个线程通过互斥 `mutex` 来保护它。每个线程在修改 `counter` 前必须先获取,修改完成后释放。这样可以确保同一时刻只有一个线程在修改 `counter`,从而避免了数据竞争问题[^2]。 ### 注意事项 - **死问题**:互斥的使用可能会导致死问题。死是指两个或多个线程互相等待对方释放资源,导致程序无法继续执行。为了避免死,应该尽量减少的嵌套使用,并确保的获取和释放顺序一致[^1]。 - **的粒度**:的粒度应该尽可能小,即在需要保护共享资源的最小范围内获取和释放。这样可以减少线程阻塞的时间,提高程序的并发性能。 - **异常处理**:在使用互斥时,建议使用 `try...finally` 结构来确保即使在发生异常的情况下,也能被正确释放。例如: ```python mutex.acquire() try: # 操作共享资源 finally: mutex.release() ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值