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.每次第一个线程释放锁,两个程序都要继续抢上锁

  

总结

锁的好处:

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

锁的坏处:

  • 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
  • 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
原文地址:https://www.cnblogs.com/venicid/p/7966771.html