wgij007 发表于 2023-7-27 18:22:05

为什么程序用多线程运行不完整呢

本帖最后由 wgij007 于 2023-7-28 08:09 编辑

import wmi
import threading# 多线程
import time

c = wmi.WMI()
lock = threading.Lock()


def sn_test():
    ##lock.acquire()
    print (11)
    i = 0
    while i < 2:
      print (22)
      for physical_disk in c.Win32_DiskDrive():
            print (33)
            sn = physical_disk.SerialNumber.strip()
            print (sn)
            time.sleep(0.2)# 刷新速度
      i += 1
    ##timeout = 0.5




def thread01():
    thread01_a = threading.Thread(name = 'python_thread01', target = sn_test)
    thread01_a.setDaemon(True)
    thread01_a.start()# 线程开始


if __name__ == '__main__':
    thread01()


直接运行 sn_test() 正常没问题
11
22
33
3035323042363737323835393130463320202020
33
4141303030303030303030303030303038303333
22
33
3035323042363737323835393130463320202020
33
4141303030303030303030303030303038303333
输出结束,返回值是.


但经过thread01()
11
22
输出结束,返回值是.

,就只到22那,就终止了。如果不锁就会出错,不知为什么,求解

鱼cpython学习者 发表于 2023-7-27 18:22:06

很玄学的问题,我也不知道为什么
import threading# 多线程
import time

lock = threading.Lock()


def sn_test():
    import wmi
    c = wmi.WMI()

    # lock.acquire()
    print(11)
    i = 0
    while i < 2:
      print(22)
      for physical_disk in c.Win32_DiskDrive():
            print(33)
            sn = physical_disk.SerialNumber.strip()
            print(sn)
            time.sleep(0.2)# 刷新速度
      i += 1
    # timeout = 0.5


def thread01():

    thread01_a = threading.Thread(name='python_thread01', target=sn_test)
    thread01_a.setDaemon(True)
    thread01_a.start()# 线程开始
    thread01_a.join()


if __name__ == '__main__':
    thread01()

setDaemon会把线程变为守护线程,主线程不会等待守护线程完成后再结束,它会强制结束,所以加个.join()保证线程的执行
我在我这里测试后发现会报错“发生意外”,把import wmi和c = wmi.WMI()移到子线程后就不报错了

isdkz 发表于 2023-7-27 18:22:27

在你提供的代码中,有一个关于多线程的问题,导致程序运行不完整的现象。问题在于在多线程环境下,可能会出现数据竞争(Data Race)的情况,即多个线程同时访问和修改共享数据,从而导致程序的行为不可预测。

在代码中, sn_test() 函数涉及对共享资源的访问,这里主要是 c 对象,它是 wmi.WMI() 的一个实例,同时多个线程对其进行读取操作。由于多线程同时对 c 进行操作,可能会导致数据不一致的情况,进而引发问题。

为了解决这个问题,你可以使用线程锁(Lock)来保护对共享资源的访问,确保在任意时刻只有一个线程能够访问共享资源。你在代码中已经尝试过使用锁,但是由于锁的位置不正确,导致锁没有起到作用。

正确的做法是在 sn_test() 函数内部使用锁来保护对共享资源 c 的访问,具体做法是:

def sn_test():
    lock.acquire()# 获取锁
    try:
      print(11)
      i = 0
      while i < 2:
            print(22)
            for physical_disk in c.Win32_DiskDrive():
                print(33)
                sn = physical_disk.SerialNumber.strip()
                print(sn)
                time.sleep(0.2)# 刷新速度
            i += 1
    finally:
      lock.release()# 释放锁


通过将对 c 的访问放在 lock.acquire() 和 lock.release() 之间,保证了在一个线程执行 sn_test() 函数时,其他线程无法同时访问 c 。这样就避免了多线程下对共享资源的竞争问题,应该能够解决程序运行不完整的问题。

请注意,在使用锁的情况下,可能会降低程序的并发性能,因为每个线程在访问共享资源时都需要等待获取锁。在设计多线程程序时,需要权衡使用锁的必要性和对性能的影响。如果对于性能要求较高,可以考虑使用其他同步机制,如信号量(Semaphore)或条件变量(Condition),具体选择取决于应用场景。

Mike_python小 发表于 2023-7-27 18:22:36

问题分析:
根据您提供的代码,出现线程终止的原因可能是在sn_test()函数内没有释放锁。同时,您在thread01()函数内创建了一个线程,并将其设置为守护线程,但是没有阻塞主线程,所以主线程很快就会结束,导致守护线程也随之终止。

解决方案:
1. 在sn_test()函数中添加锁机制,确保多个线程之间对共享资源的互斥访问。您可以通过以下方式修改代码:


def sn_test():
    lock.acquire()
    print(11)
    i = 0
    while i < 2:
      print(22)
      for physical_disk in c.Win32_DiskDrive():
            print(33)
            sn = physical_disk.SerialNumber.strip()
            print(sn)
            time.sleep(0.2)# 刷新速度
      i += 1
    lock.release()


2. 修改thread01()函数,在启动线程后,使用thread01_a.join()阻塞主线程,等待子线程执行完毕后再结束主线程。修改后的代码如下:


def thread01():
    thread01_a = threading.Thread(name='python_thread01', target=sn_test)
    thread01_a.setDaemon(True)
    thread01_a.start()# 线程开始
    thread01_a.join()# 阻塞主线程,等待子线程执行完毕

if __name__ == '__main__':
    thread01()


应用以上修改后,重新运行程序,您应该能够看到线程能够正常执行并等待子线程完成后再退出主线程。

球一个最佳答案谢谢啦!这对我非常重要!{:10_254:}{:10_254:}{:10_254:}

陶远航 发表于 2023-7-27 18:22:40

根据你提供的代码,问题可能是由于多线程引起的并发访问问题。在多线程环境下,当多个线程同时访问共享资源时,可能会导致竞争条件和不确定行为。

在你的代码中,sn_test()函数被作为线程运行,并且该函数内部对全局变量c进行了访问,可能出现竞争条件。此外,你还尝试使用lock对象进行锁定,但没有正确地使用它。

你可以尝试使用锁机制来解决这个问题,确保只有一个线程能够访问sn_test()函数中的关键部分。以下是修改后的代码示例:

import wmi
import threading
import time

c = wmi.WMI()
lock = threading.Lock()

def sn_test():
    lock.acquire()# 获取锁
    print (11)
    i = 0
    while i < 2:
      print (22)
      for physical_disk in c.Win32_DiskDrive():
            print (33)
            sn = physical_disk.SerialNumber.strip()
            print (sn)
      time.sleep(0.2)# 刷新速度
      i += 1
    lock.release()# 释放锁

def thread01():
    thread01_a = threading.Thread(name='python_thread01', target=sn_test)
    thread01_a.setDaemon(True)
    thread01_a.start()

if __name__ == '__main__':
    thread01()


在修改后的代码中,通过在关键部分之前调用lock.acquire()来获取锁,确保只有一个线程能够访问关键部分。然后,在关键部分执行完后,调用lock.release()释放锁。

这样修改后,你应该能够看到预期的输出。希望这能解决你的问题!如果还有其他疑问,请随时提问。
如果问题已经解决,请设置最佳答案

wgij007 发表于 2023-7-28 08:02:34

isdkz 发表于 2023-7-27 18:22
在你提供的代码中,有一个关于多线程的问题,导致程序运行不完整的现象。问题在于在多线程环境下,可能会出 ...

一样只到了22那里

wgij007 发表于 2023-7-28 08:04:09

陶远航 发表于 2023-7-27 18:22
根据你提供的代码,问题可能是由于多线程引起的并发访问问题。在多线程环境下,当多个线程同时访问共享资源 ...

一样只到了22那里

wgij007 发表于 2023-7-28 08:04:39

Mike_python小 发表于 2023-7-27 18:22
问题分析:
根据您提供的代码,出现线程终止的原因可能是在sn_test()函数内没有释放锁。同时,您在thread01 ...

还是会报错

wgij007 发表于 2023-7-29 08:13:25

鱼cpython学习者 发表于 2023-7-28 10:24
很玄学的问题,我也不知道为什么

setDaemon会把线程变为守护线程,主线程不会等待守护线程完成后再结束 ...

单独这样是没报错,但与其他程序起,还是有问题,没用子进程来做,都是OK的,也不知为什么。

鱼cpython学习者 发表于 2023-7-29 11:26:27

wgij007 发表于 2023-7-29 08:13
单独这样是没报错,但与其他程序起,还是有问题,没用子进程来做,都是OK的,也不知为什么。

问题是什么?没运行完成就停止?还是报的什么错

wgij007 发表于 2023-7-29 17:01:19

这子线程循环时运行栓测,会卡死。这用在其他地方就没问题,可以与WMI这块不合吧,搞了几天都没找出问题,换种方法了。
页: [1]
查看完整版本: 为什么程序用多线程运行不完整呢