zoukankan      html  css  js  c++  java
  • 互斥锁、死锁和递归锁

    一、互斥锁(Mutex)

       在上节最后我们讲到了线程安全,线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

      threading模块中定义了Lock类,可以方便的处理锁定: 

    #创建锁
    lock = threading.Lock()
    #锁定
    lock.acquire(blocking=True, timeout=-1) 
    #释放 
    lock.release() 

      还是以上节实例为例:

    # -*- coding: UTF-8 -*-
    
    import threading
    
    
    class MyThread(threading.Thread):
    
        def run(self):
            global n
            lock.acquire()
            n += 1
            lock.release()
            print(self.name + ' set n to ' + str(n))
    
    n = 0
    lock = threading.Lock()
    
    if __name__ == '__main__':
    
        for i in range(5):
            t = MyThread()
            t.start()
    
        print('final num: %d' % n)
    

      输出:

    Thread-1 set n to 1
    Thread-2 set n to 2
    Thread-3 set n to 3
    Thread-4 set n to 4
    Thread-5 set n to 5
    final num: 5
    

      加锁之后,我们可以确保数据的正确性

    二、死锁

      死锁是指一个资源被多次调用,而多次调用方都未能释放该资源就会造成一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

      2.1 一个线程内部多次加锁却没有释放  

    import threading
    
    
    class MyThread(threading.Thread):
    
        def run(self):
            global n1, n2
            lock.acquire()   # 加锁
            n1 += 1
            print(self.name + ' set n1 to ' + str(n1))
            lock.acquire()   # 再次加锁
            n2 += n1
            print(self.name + ' set n2 to ' + str(n2))
            lock.release()
            lock.release()
    
    n1, n2 = 0, 0
    lock = threading.Lock()
    
    if __name__ == '__main__':
        thread_list = []
        for i in range(5):
            t = MyThread()
            t.start()
            thread_list.append(t)
        for t in thread_list:
            t.join()
        print('final num:%d ,%d' % (n1, n2))
    

      结果:

    Thread-1 set n1 to 1
    
    # 会一直等待
    

      2.2 多个程序间相互调用引起死锁

    import threading,time
     
    def run1():
        print("grab the first part data")
        lock.acquire()
        global num
        num +=1
        lock.release()
        return num
    def run2():
        print("grab the second part data")
        lock.acquire()
        global  num2
        num2+=1
        lock.release()
        return num2
    def run3():
        lock.acquire()
        res = run1()
        print('--------between run1 and run2-----')
        res2 = run2()
        lock.release()
        print(res,res2)
     
     
    if __name__ == '__main__':
     
        num,num2 = 0,0
        lock = threading.Lock()
        for i in range(10):
            t = threading.Thread(target=run3)
            t.start()
     
    while threading.active_count() != 1:
        print(threading.active_count())
    else:
        print('----all threads done---')
        print(num,num2) 

     三、递归锁

      上述两个问题都可以使用python的递归锁解决 

    # 递归锁
    rlock = threading.RLOCK()
    

      RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。这里以例1为例,如果使用RLock代替Lock,则不会发生死锁:

      

    # -*- coding: UTF-8 -*-
    import threading
    
    
    class MyThread(threading.Thread):
    
        def run(self):
            global n1, n2
            lock.acquire()   # 加锁
            n1 += 1
            print(self.name + ' set n1 to ' + str(n1))
            lock.acquire()   # 再次加锁
            n2 += n1
            print(self.name + ' set n2 to ' + str(n2))
            lock.release()
            lock.release()
    
    n1, n2 = 0, 0
    lock = threading.RLock()
    
    if __name__ == '__main__':
        thread_list = []
        for i in range(5):
            t = MyThread()
            t.start()
            thread_list.append(t)
        for t in thread_list:
            t.join()
        print('final num:%d ,%d' % (n1, n2))
    

      输出:

    Thread-1 set n1 to 1
    Thread-1 set n2 to 1
    Thread-2 set n1 to 2
    Thread-2 set n2 to 3
    Thread-3 set n1 to 3
    Thread-3 set n2 to 6
    Thread-4 set n1 to 4
    Thread-4 set n2 to 10
    Thread-5 set n1 to 5
    Thread-5 set n2 to 15
    final num:5 ,15
    

      

  • 相关阅读:
    asp中动态include的方法
    asp存储过程使用大全
    用vb6写asp组件的简单例子
    asp中遍历一些对象(request,session,Application)
    查看ASP Session 变量的小工具
    层不能跨框架(包括TEXTAREA)显示的解决办法
    保存远程图片到本地 同时取得第一张图片并创建缩略图
    使用.Net开发asp组件
    使用ASP在IIS创建WEB站点
    解析notes自带的rtf javaapplet编辑器
  • 原文地址:https://www.cnblogs.com/bigberg/p/7910024.html
Copyright © 2011-2022 走看看