zoukankan      html  css  js  c++  java
  • 线程与进程--线程三把锁

    为什么要有三把锁

    学习三把锁时候我们需要先知道为什么要有三把锁
      全局资源(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

  • 相关阅读:
    hdu 2050 折线分割平面 递推
    hdu 2044 一只小蜜蜂 斐波那契数列 递推
    hdu 2018 母牛的故事 递推
    hdu 2084 数塔 dp 动态规划
    Linux 常用协议结构体及详解
    【ArcEngine入门与提高】Element(元素)、Annotation(注记)旋转
    AO总结10:MapControl控件
    esriControlsMousePointer 控制鼠标指针
    图解VS2010打包全过程(转)
    ArcEngine中打开各种数据源(WorkSpace)的连接(转)
  • 原文地址:https://www.cnblogs.com/935415150wang/p/7201024.html
Copyright © 2011-2022 走看看