You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TKinter程序无响应求助:线程使用后仍异常,含文件占用错误

问题描述

我正在运行一个包含3个测试用例的Tkinter程序,但程序出现无响应状态。尝试用线程解决后情况依旧,还出现错误提示:The process cannot access the file because it is being used by another process.。不确定线程是否会在设定时长后终止,看起来线程并未结束,恳请帮忙检查代码。

用户提供的代码:

import threading
from tkinter import *
import time
import random
import os 
import datetime
import Test_cases

Tc =Test_cases.Test()

class Blocking():
    def __init__(self):
        self.window_main = Tk(className='Naren-App',)
        self.window_main.geometry("600x300")
        Label(self.window_main, text="Stability Tool").place(x=460, y=100, anchor="center")

        # adding a label Frame to the Main window
        self.Frame_window = LabelFrame(self.window_main, text = 'Test Cases')
        self.Frame_window.config(width=400, height=800)
        self.Frame_window.place(x=300, y=200, anchor="center")

        self.var1 = IntVar()
        self.Check_Button_1 = Checkbutton(self.Frame_window, text = "Screen_ON_OFF_Test",variable=self.var1).pack()
        self.var2 = IntVar()
        self.Check_Button_2 = Checkbutton(self.Frame_window, text = "WWAN_LPM_To_Online",variable=self.var2).pack()
        self.var3 = IntVar()
        self.Check_Button_3 = Checkbutton(self.Frame_window, text = "Get_Device_State",variable=self.var3).pack()
        Label(self.Frame_window, text="Enter Each Test Duration in Sec").pack()
        self.Duration = IntVar() # to set default value 
        self.TestDuration = Entry(self.Frame_window, textvariable=self.Duration).pack()



        #submitBtn = Button(self.Frame_window, text="submit", command=lambda:submit(Check_Button_1.get(),Check_Button_2.get(),Check_Button_3.get()))
        self.submitBtn = Button(self.Frame_window, text="submit", bg='blue',state=NORMAL,command=self.submit)
        self.submitBtn.pack()


        #stability 
        self.Frame_window = LabelFrame(self.window_main, text = 'Stability')
        self.Frame_window.config(width=400, height=800)
        self.Frame_window.place(x=600, y=200, anchor="center")

        self.var4 = IntVar()
        self.Test_Name_Check_button = Checkbutton(self.Frame_window, text = "Test_Name",variable=self.var4).pack()
        self.var5 = IntVar()
        self.NumberOf_Iterations_Check_button = Checkbutton(self.Frame_window, text = "NumberOf_Iterations",variable=self.var5).pack()
        self.var6 = IntVar()
        self.NumberOf_Hours_Check_button = Checkbutton(self.Frame_window, text = "NumberOf_Hours",variable=self.var6).pack()

        self.submitBtn2 = Button(self.Frame_window, text="submit", bg='blue', state =DISABLED,command=self.submit)
        self.submitBtn2.pack()
        self.window_main.mainloop()
    
    def submit(self):
            print("var1: %d,\n var2: %d,\nvar3: %d,\nDuration: %d" % (self.var1.get(), self.var2.get() , self.var3.get(), self.Duration.get()))
            TestDuration = int(self.Duration.get())
            print("Test Duration2:", TestDuration)
            Tc.Duration = TestDuration
            print("Passing Duration:", Tc.Duration)
            self.submitBtn['bg']='blue'
            self.submitBtn['state']=DISABLED
            if self.var1.get() == 1 : 
                    print("Starting Screen on off \n")
                    print("Screen On OFF Test Will run For:",TestDuration ,"sec \n")
                    T1=threading.Thread(target=Tc.Screen_ON_OFF()).start()
                    time.sleep(TestDuration+5)
                    #T1.join()
            if self.var2.get() == 1 :
                    print("Starting LPM to Online \n")
                    print("LPM to Online Test Will run For:",TestDuration ,"sec \n")
                    T2=threading.Thread(target=Tc.LPM_To_Online()).start()
                    time.sleep(TestDuration+5)
            if self.var3.get() == 1 :
                    print("Getting device state \n")
                    print("Getting device statet Will run For:",TestDuration ,"sec \n")
                    T1=threading.Thread(target=Tc.Get_Device_State()).start()
                    time.sleep(TestDuration+5)
            return Label(self.window_main, text="Submitted!").pack()


def main():
    block = Blocking()
   
if __name__ == '__main__':
    main() 
问题分析与修复方案

1. 线程创建错误导致UI阻塞

你创建线程的写法完全错误:threading.Thread(target=Tc.Screen_ON_OFF()).start() 会直接在主线程中执行Tc.Screen_ON_OFF(),而非把它作为目标函数交给子线程执行。这会导致主线程被测试逻辑卡死,Tkinter事件循环无法运行,程序直接无响应。

正确写法是传入函数对象(不要加括号):

T1 = threading.Thread(target=Tc.Screen_ON_OFF)
T1.start()

2. time.sleep()阻塞主线程

submit方法中每次启动线程后调用time.sleep(TestDuration+5),会让主线程进入休眠状态,完全阻塞Tkinter的事件循环,这是程序无响应的核心原因。

解决方式:

  • 删掉所有time.sleep()调用
  • 让测试线程自身管理运行时长,或用Tkinter的after()方法定期检查线程状态,而非在主线程中等待

3. 文件占用错误

The process cannot access the file because it is being used by another process 大概率是Test_cases模块中存在以下问题:

  • 多个测试用例同时操作同一个文件,且未正确关闭
  • 文件操作未加锁,导致线程间资源竞争

修复方式:

  • 所有文件操作使用with语句自动关闭文件:
    with open("test_log.txt", "a", encoding="utf-8") as f:
        f.write(f"{datetime.datetime.now()} - 测试日志\n")
    
  • 多线程操作同一文件时加锁:
    file_lock = threading.Lock()
    
    def safe_write_log(content):
        with file_lock:
            with open("test_log.txt", "a", encoding="utf-8") as f:
                f.write(content + "\n")
    

4. 线程未正确终止

要确保测试线程能在设定时长后自动停止,需在Test_cases的测试方法中加入超时逻辑:

class Test:
    def __init__(self):
        self.duration = 0

    def Screen_ON_OFF(self):
        start_time = time.time()
        while time.time() - start_time < self.duration:
            # 执行你的测试逻辑
            time.sleep(1)  # 模拟测试间隔
        print("Screen_ON_OFF测试结束")

修复后的完整代码示例

import threading
from tkinter import *
import time
import datetime
import Test_cases

Tc = Test_cases.Test()
file_lock = threading.Lock()  # 文件操作锁

class Blocking():
    def __init__(self):
        self.window_main = Tk(className='Naren-App')
        self.window_main.geometry("900x500")  # 调整窗口大小避免控件重叠
        Label(self.window_main, text="Stability Tool").place(x=450, y=50, anchor="center")

        # 测试用例框架
        self.test_frame = LabelFrame(self.window_main, text='Test Cases')
        self.test_frame.config(width=400, height=400)
        self.test_frame.place(x=200, y=250, anchor="center")

        self.var1 = IntVar()
        Checkbutton(self.test_frame, text="Screen_ON_OFF_Test", variable=self.var1).pack(pady=5)
        self.var2 = IntVar()
        Checkbutton(self.test_frame, text="WWAN_LPM_To_Online", variable=self.var2).pack(pady=5)
        self.var3 = IntVar()
        Checkbutton(self.test_frame, text="Get_Device_State", variable=self.var3).pack(pady=5)
        
        Label(self.test_frame, text="Enter Each Test Duration in Sec").pack(pady=10)
        self.Duration = IntVar(value=60)  # 设置默认时长
        Entry(self.test_frame, textvariable=self.Duration).pack(pady=5)

        self.submitBtn = Button(self.test_frame, text="submit", bg='blue', state=NORMAL, command=self.submit)
        self.submitBtn.pack(pady=20)

        # 稳定性框架
        self.stability_frame = LabelFrame(self.window_main, text='Stability')
        self.stability_frame.config(width=400, height=400)
        self.stability_frame.place(x=700, y=250, anchor="center")

        self.var4 = IntVar()
        Checkbutton(self.stability_frame, text="Test_Name", variable=self.var4).pack(pady=5)
        self.var5 = IntVar()
        Checkbutton(self.stability_frame, text="NumberOf_Iterations", variable=self.var5).pack(pady=5)
        self.var6 = IntVar()
        Checkbutton(self.stability_frame, text="NumberOf_Hours", variable=self.var6).pack(pady=5)

        self.submitBtn2 = Button(self.stability_frame, text="submit", bg='blue', state=DISABLED, command=self.submit)
        self.submitBtn2.pack(pady=20)

        # 状态提示标签
        self.status_label = Label(self.window_main, text="")
        self.status_label.place(x=450, y=450, anchor="center")

        self.window_main.mainloop()
    
    def submit(self):
        var1 = self.var1.get()
        var2 = self.var2.get()
        var3 = self.var3.get()
        TestDuration = int(self.Duration.get())

        print(f"var1: {var1},\nvar2: {var2},\nvar3: {var3},\nDuration: {TestDuration}")
        Tc.Duration = TestDuration
        print("Passing Duration:", Tc.Duration)

        self.submitBtn['state'] = DISABLED
        self.status_label.config(text="测试正在运行...")

        # 启动选中的测试线程
        threads = []
        if var1 == 1:
            print("Starting Screen on off \n")
            print(f"Screen On OFF Test Will run For: {TestDuration} sec \n")
            t = threading.Thread(target=Tc.Screen_ON_OFF)
            threads.append(t)
            t.start()
        if var2 == 1:
            print("Starting LPM to Online \n")
            print(f"LPM to Online Test Will run For: {TestDuration} sec \n")
            t = threading.Thread(target=Tc.LPM_To_Online)
            threads.append(t)
            t.start()
        if var3 == 1:
            print("Getting device state \n")
            print(f"Getting device state Will run For: {TestDuration} sec \n")
            t = threading.Thread(target=Tc.Get_Device_State)
            threads.append(t)
            t.start()

        # 定期检查线程是否全部完成
        def check_threads():
            all_done = all(not t.is_alive() for t in threads)
            if all_done:
                self.submitBtn['state'] = NORMAL
                self.status_label.config(text="测试完成!")
            else:
                self.window_main.after(1000, check_threads)
        
        self.window_main.after(1000, check_threads)


def main():
    block = Blocking()
   
if __name__ == '__main__':
    main() 

额外优化说明

  • 控件变量赋值:原代码中self.Check_Button_1 = Checkbutton(...).pack()会让变量等于None(pack()返回值),实际不需要保存按钮对象,直接调用pack()即可
  • 窗口布局:调整了窗口大小和控件位置,避免两个LabelFrame重叠
  • 状态反馈:添加了状态标签,让用户直观了解测试运行状态

内容的提问来源于stack exchange,提问作者NBK_Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 02:50:23