我对锁的理解:
锁 即是对资源的一种占有,锁的是资源而不是线程。
一条线程在使用某项资源时,获取了锁,那么此时 锁 的状态就是锁住的。如果在该线程未释放锁时,其他线程就无法获取锁,也就无法使用资源。
用下面一段程序在简单解释一下:
import threading import logging import time total = 0 lock = threading.Lock() def get_logger(): logger = logging.getLogger("threading_eg") logger.setLevel(logging.DEBUG) fh = logging.FileHandler("C:\\Users\Administrator\Desktop\\test\\threading.log") fmt = '%(asctime)s - %(name)s - %(threadName)s - %(message)s' formatter = logging.Formatter(fmt) fh.setFormatter(formatter) logger.addHandler(fh) return logger def plus_total(amount, logger): global total logger.debug('lock not acquire') lock.acquire() logger.debug('lock has acquire') total += amount print(total) lock.release() def m_total(amount, logger): global total lock.acquire() total -= amount print(total) logger.debug('lock not released') time.sleep(10) lock.release() logger.debug('lock has released') logger = get_logger() my_thread1 = threading.Thread( target=m_total, args=(5, logger)) my_thread2 = threading.Thread( target=plus_total, args=(5, logger)) logger.debug('thread1 start') my_thread1.start() time.sleep(3) logger.debug('thread2 start') my_thread2.start()
第一个函数不用说,日志记录
第二个函数将一个全局变量加5后输出,第三个函数将一个全局变量减5后输出。在每个函数执行的第一行都需要获取锁,在第三个函数获取锁后,等待10s再释放锁。
在主程序中,先构造了一个logger对象,然后构造了两个线程,第一个线程启动后等待3s再启动启动第二个线程。
看结果:
在主线程中首先线程1启动,线程1在很短时间内执行完了m_total函数大部分,直到sleep需要等待10s,3s后线程2启动,而此时锁还未被释放,所以线程2无法执行plus_total中的加法内容。过了10s后,线程1将锁释放,此时线程2也获得了锁,可以执行加法内容了。
这里就充分体现了锁的作用。
lock是一个低级的锁,即同一线程无法多次获得锁。为了解决这个方法,可以利用 重入锁 Rlock,同一线程可以多次获取该,。该线程也必须释放相同次数该锁。
也就是说,Rlock内部有一个计数器,当值为0时处于未锁定状态,当acquire时值+1,release时值-1。
看下面这段程序:
import threading import logging total = 0 lock = threading.Lock() def get_logger(): logger = logging.getLogger("threading_eg") logger.setLevel(logging.DEBUG) fh = logging.FileHandler("C:\\Users\Administrator\Desktop\\test\\threading2.log") fmt = '%(asctime)s - %(name)s - %(threadName)s - %(message)s' formatter = logging.Formatter(fmt) fh.setFormatter(formatter) logger.addHandler(fh) return logger def plus_total(amount, logger): global total logger.debug('lock not acquire') lock.acquire() logger.debug('lock has acquire') total += amount print(total) lock.release() def m_total(amount, logger): global total lock.acquire() logger.debug('lock has acquire') total -= amount print(total) logger.debug('lock not released') logger = get_logger() m_total(5, logger) plus_total(5, logger)
大体上没有什么改变,在主线程里同时调用了两个函数,而m_total在获取锁之后没有释放,所以plus_total无法完成。这段程序也因此是一直停滞,无法完成。
结果:可以看出主线程的plus_total一直没有获取锁
接下来将锁改为RLock:
lock = threading.RLock()
执行后结果如下:
虽然m_total没有释放锁,但是plus_total同样获取了锁。这就是RLock的特性,即同一线程可以多次获取该锁。