什么是竞态条件?
竞态条件是指多个线程在访问和操作共享资源时,由于执行顺序的不确定性而导致结果不确定或出现错误。
示例1:
''' 竞态条件是指多个线程在访问和操作共享资源时,由于执行顺序的不确定性而导致结果不确定或出现错误。 ''' import threading # 共享变量 counter = 0 # 线程函数 def increment(): global counter ''' 在Python中,使用下划线 _ 作为一个临时变量的命名约定是很常见的。这个约定表明该变量的值不会被使用,或者不关心该变量的具体值。 for _ in range(100000) 表示一个循环,循环执行10万次。在每次循环迭代中,由于并不需要使用循环变量的值,因此使用下划线 _ 来表示这个临时变量。 这种情况下,使用下划线 _ 可以告诉读者,这个循环变量的值并不重要,只是为了控制循环次数而已。 通过使用下划线 _,可以避免创建一个不必要的变量,并提高代码的可读性。 ''' for _ in range(100000): counter += 1 def decrement(): global counter for _ in range(100000): counter -= 1 def main(): # 创建两个线程 t1 = threading.Thread(target=increment) t2 = threading.Thread(target=decrement) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() # 打印最终结果 print("Counter:", counter) if __name__ == '__main__': main()
输出:Counter: 0
多次执行从结果上,是对的。多线程存在竞态条件,可能导致结果不正确。(有些结果是正确的,有写结果是错误的,存在概率问题)
在这段代码中,两个线程分别对共享变量 counter
进行加一和减一操作。由于这两个线程同时访问和修改 counter
变量,可能会导致竞态条件的问题。
在某些情况下,当一个线程正在执行增加操作时,另一个线程可能同时执行减少操作,这可能导致结果不可预测。
然而,即使竞态条件发生,也不能保证最终结果一定是0。因为在 Python 中, counter += 1
和 counter -= 1
操作并不是原子操作,它们实际上是多个步骤的组合。
例如,在 counter += 1
操作中,首先需要读取 counter
的当前值,然后进行加一操作,最后将新值写回到 counter
中。类似地,counter -= 1
操作也包括读取、减一和写回这三个步骤。
由于这些操作不是原子的,两个线程之间的交替执行可能会导致一些操作被覆盖或丢失,从而导致最终结果出现错误。
示例2
1 import threading 2 3 4 # 全局变量 5 g_num = 0 6 7 8 # 对g_num进行加操作 9 def sum_num1(): 10 for i in range(1000000): 11 global g_num 12 g_num += 1 13 14 print("g_num1:", g_num) 15 16 17 # 对g_num进行加操作 18 def sum_num2(): 19 for i in range(1000000): 20 global g_num 21 g_num += 1 22 23 print("g_num2:", g_num) 24 25 26 if __name__ == '__main__': 27 # 创建子线程 28 sum1_thread = threading.Thread(target=sum_num1) 29 sum2_thread = threading.Thread(target=sum_num2) 30 31 # 启动线程 32 sum1_thread.start() 33 sum2_thread.start() 34 sum1_thread.join() 35 sum2_thread.join() 36 print("Final g_num:", g_num)
输出:(存在出现问题的概率,模拟出来有概率)
g_num1: 1295051
g_num2: 1999991
Final g_num: 1999991
解决方法
为了解决这个问题,可以使用同步机制(如锁)来确保每次只有一个线程能够访问和修改共享变量
1 import threading 2 3 # 全局变量 4 g_num = 0 5 # 全局变量作为锁对象(保证多个线程使用的是同一把锁)。在多个线程中通过 with lock: 语句来获取该锁。 6 lock = threading.Lock() 7 8 9 # 对g_num进行加操作 10 def sum_num1(): 11 global g_num 12 for i in range(1000000): 13 with lock: 14 g_num += 1 15 print("g_num1:", g_num) 16 17 18 # 对g_num进行加操作 19 def sum_num2(): 20 global g_num 21 for i in range(1000000): 22 with lock: # 通过with语句实现自动上锁、解锁 23 g_num += 1 24 print("g_num2:", g_num) 25 26 27 if __name__ == '__main__': 28 # 创建子线程 29 sum1_thread = threading.Thread(target=sum_num1) 30 sum2_thread = threading.Thread(target=sum_num2) 31 32 # 启动线程 33 sum1_thread.start() 34 sum2_thread.start() 35 36 # 等待子线程结束 37 sum1_thread.join() 38 sum2_thread.join() 39 40 # 打印最终结果 41 print("Final g_num:", g_num)
输出:
g_num1: 1841952
g_num2: 2000000
Final g_num: 2000000
标签:__,thread,counter,共享资源,threading,num,线程,竞态,多线程 From: https://www.cnblogs.com/allenxx/p/17589607.html