zoukankan      html  css  js  c++  java
  • 8 解决多线程对共享数据出错

    1. 添加flag

    from threading import Thread
    import time
    
    g_num = 0
    g_flag = 1
    
    def test1():
        global g_num
        global g_flag
    
        if g_flag == 1:
            for i in range(1000000):
                g_num += 1
            g_flag = 0
    
        print("---test1---g_num=%d"%g_num)
    
    
    def test2():
        global g_num
        global g_flag 
        if g_flag != 1:           #test2判断不成功,直接执行print语句,如何让它一直判断下去
            for i in range(1000000): 
                g_num += 1
    
        print("---test2---g_num=%d"%g_num)
    
    
    p1 = Thread(target=test1)
    p1.start()
    
    
    p2 = Thread(target=test2)
    p2.start()
    
    print("---g_num=%d---"%g_num)

         

    2.轮询:永无休止的进行flag判断

    from threading import Thread
    import time
    
    g_num = 0
    g_flag = 1
    
    def test1():
        global g_num
        global g_flag
        if g_flag == 1:
            for i in range(1000000):
                g_num += 1
            g_flag = 0
    
        print("---test1---g_num=%d"%g_num)
    
    def test2():
        global g_num
        global g_flag
        #轮询
        while True:
            if g_flag != 1:
                for i in range(1000000):
                    g_num += 1
                break
    
        print("---test2---g_num=%d"%g_num)
    
    
    p1 = Thread(target=test1)
    p1.start()
    
    #time.sleep(3) #取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢?
    
    p2 = Thread(target=test2)
    p2.start()
    
    print("---g_num=%d---"%g_num)

     

    3.互斥锁

      当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制

      线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

      互斥锁为资源引入一个状态:锁定/非锁定。

    • threading模块中定义了Lock类,可以方便的处理锁定:
    #创建锁
    mutex = threading.Lock()
    #锁定
    mutex.acquire([blocking])
    #释放
    mutex.release()

    其中,锁定方法acquire可以有一个blocking参数。

    • 如果设定blocking为True,则当前线程会堵塞,直到获取到这个锁为止(如果没有指定,那么默认为True)
    • 如果设定blocking为False,则当前线程不会堵塞

      1)互斥锁程序

    from threading import Thread, Lock
    import time
    
    g_num = 0
    
    def test1():
        global g_num
        #这个线程和test2线程都在抢着 对这个锁 进行上锁,如果有1方成功的上锁,那么导致另外
        #一方会堵塞(一直等待)到这个锁被解开为止
        mutex.acquire()
        for i in range(1000000):
            g_num += 1
        mutex.release()#用来对mutex指向的这个锁 进行解锁,,,只要开了锁,那么接下来会让所有因为
                        #这个锁 被上了锁 而堵塞的线程 进行抢着上锁
    
        print("---test1---g_num=%d"%g_num)
    
    def test2():
        global g_num
        mutex.acquire()
        for i in range(1000000):
            g_num += 1
        mutex.release()
    
        print("---test2---g_num=%d"%g_num)
    
    #创建一把互斥锁,这个锁默认是没有上锁的
    mutex = Lock()
    
    p1 = Thread(target=test1)
    p1.start()
    
    #time.sleep(3) #取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢?
    
    p2 = Thread(target=test2)
    p2.start()
    
    print("---g_num=%d---"%g_num)

        

    • 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了

           

    4.互斥锁的问题

        

      通知机制:第2个线程去睡觉,等第1个执行完成去通知第2个线程,不是轮询机制

      1)上锁放在for里面

    from threading import Thread, Lock
    import time
    
    g_num = 0
    
    def test1():
        global g_num
        for i in range(1000000):
            mutex.acquire()
            g_num += 1
            mutex.release()
    
        print("---test1---g_num=%d"%g_num)
    
    def test2():
        global g_num
        for i in range(1000000):
            mutex.acquire()
            g_num += 1
            mutex.release()
    
        print("---test2---g_num=%d"%g_num)
    
    mutex = Lock()
    
    p1 = Thread(target=test1)
    p1.start()
    
    p2 = Thread(target=test2)
    p2.start()
    
    print("---g_num=%d---"%g_num)

           

    1.每次上锁两个线程都要抢
    2.每次第一个线程释放锁,两个程序都要继续抢上锁

      

    总结

    锁的好处:

    • 确保了某段关键代码只能由一个线程从头到尾完整地执行

    锁的坏处:

    • 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
    • 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
  • 相关阅读:
    心态--编程+成长
    【Oracle】容易犯的错误和技巧集合
    【WPF】DataGrid的Row样式设置
    【WPF】给TextBox添上Label
    【Oracle】异常信息的加工处理
    【.Net 】Json和Xml解析
    【Win32 API】利用SendMessage实现winform与wpf之间的消息传递
    【WCF】利用WCF实现上传下载文件服务
    【Oracle】实现Oracle数据库对象的一键升级
    感触
  • 原文地址:https://www.cnblogs.com/venicid/p/7966771.html
Copyright © 2011-2022 走看看