首页 > 代码库 > 线程与进程--线程三把锁

线程与进程--线程三把锁

为什么要有三把锁

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

 

同步锁 (Lock)又名互斥锁

互斥锁概念

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

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

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 "I am %s, set counter:%s" % (self.name, counter)  
            mutex.release()   释放进程所 
 
if __name__ == "__main__":  
    for i in range(0, 100):  
        my_thread = MyThread()  
        my_thread.start()

 

递归锁(RLock)

在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明:

import threading  
lock = threading.Lock() #Lock对象  
lock.acquire()  
lock.acquire()  #产生了死琐。  
lock.release()  
lock.release()  
打印结果:会出现无法运行下去
import threading rLock
= threading.RLock() #RLock对象 rLock.acquire() rLock.acquire() #在同一线程内,程序不会堵塞。 rLock.release() rLock.release()

这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。threading.Condition
  可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

################这个方法作为补充######################

Condition.wait([timeout]):  
  wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
Condition.notify():
  唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all()
Condition.notifyAll()
  唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

 

 Semaphore(信号量)

Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

 

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "wyd"
# Date: 2017/7/18

import threading
import time

semaphore= threading.Semaphore(5)#这里我们只允许同时运行5个线程

def fun():

if semaphore.acquire():#这里我们占用调用一把锁原来的可使用锁数-1
print(threading.currentThread().getName()+‘get semaphore‘)#threading.currentThread().getName()查看使用的线程打印结果
time.sleep(0.5)
semaphore.release()

for i in range(20):#这里我们开启20个线程
t1=threading.Thread(target=fun)
t1.start()

=======================================打印的结果=============

Thread-1get semaphore
Thread-2get semaphore
Thread-3get semaphore
Thread-4get semaphore
Thread-5get semaphore

 

线程与进程--线程三把锁