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

Python 2.7.9子进程无法终止求助:类屏保功能实现遇阻

解决屏保子进程无法终止的问题

看起来你遇到了类似Windows屏保的逻辑实现难题——启动子进程后没法用常规方法终止,还碰到了进程ID相关的错误。我来帮你一步步排查和解决:

问题分析

  1. p.kill()/p.terminate()无效:大概率是因为strandtest.py启动时创建了自己的子进程,或者你用shell=True启动脚本(此时p.pid是shell进程的ID,而非strandtest.py本身),只终止父进程不会连带终止子进程。
  2. module' object has no attribute 'pid'错误:这个错误说明你调用os.getpgid()时传入的不是Popen实例的pid,而是误引用了某个模块(比如subprocess.pid),而不是你创建的进程对象p的pid属性。

解决方案

核心思路是让strandtest.py在独立的进程组中运行,这样我们可以一次性杀掉整个进程组,确保所有相关进程都被终止。同时修正变量引用错误,正确跟踪进程实例。

步骤1:正确启动子进程

启动strandtest.py时,添加start_new_session=True参数,让它成为新进程组的组长:

# 替换你原来的启动代码
screensaver_process = Popen(["python", "strandtest.py"], start_new_session=True)

这个参数会让子进程脱离当前进程组,自己创建一个新组,后续我们可以通过进程组ID杀掉所有关联进程。

步骤2:正确终止进程组

当检测到遥控器输入时,用进程组ID终止整个进程组,而不是单个进程:

import os
import signal

def stop_screensaver():
    global screensaver_process
    if screensaver_process is not None:
        try:
            # 获取子进程的进程组ID
            pgid = os.getpgid(screensaver_process.pid)
            # 发送SIGTERM信号终止整个进程组
            os.killpg(pgid, signal.SIGTERM)
            # 等待进程结束,避免僵尸进程
            screensaver_process.wait()
        except ProcessLookupError:
            # 如果进程已经自行结束,忽略错误
            pass
        screensaver_process = None

步骤3:完善主逻辑(类似屏保的触发与重置)

添加计时器逻辑,检测用户输入并重置计时,5秒无输入则启动屏保,有输入则终止屏保:

import lirc
import time

# 初始化变量
screen_saver_running = False
screensaver_process = None
last_input_time = time.time()

# 初始化lirc(保留你原来的代码)
sockid = lirc.init("lifetec", blocking=False)

# 主循环
while True:
    # 检测遥控器输入
    code = lirc.nextcode()
    if code:
        print(f"收到遥控器指令: {code}")
        last_input_time = time.time()
        # 如果屏保正在运行,立即终止
        if screen_saver_running:
            stop_screensaver()
            screen_saver_running = False
        # 这里添加你的菜单处理逻辑...
    
    # 5秒无输入且未启动屏保时,启动屏保
    if not screen_saver_running and (time.time() - last_input_time) > 5:
        start_screensaver()
        screen_saver_running = True
    
    # 小延迟降低CPU占用
    time.sleep(0.1)

关键注意事项

  • 确保你没有误写变量名:比如不要把p.pid写成subprocess.pid(这就是你碰到"module has no attribute pid"的原因)。
  • 避免用shell=True启动脚本:如果必须用,你需要额外处理子进程的PID,但用start_new_session=True+进程组的方式更可靠。
  • 调用wait():终止进程后调用screensaver_process.wait()可以避免僵尸进程残留。

完整修改后的代码片段

整合以上逻辑,你的代码大概会变成这样(保留你原来的LED初始化等代码):

import lirc
import time
import os
import signal
from subprocess import PIPE, Popen
from neopixel import *

# 全局变量
Volume = 60
mute = False
screen_saver_running = False
screensaver_process = None
last_input_time = time.time()

# LED配置(保留你的设置)
LEDS = 100
PIN = 18
BRIGHTNESS = 255
R = 255
G = 255
B = 255
LED_CHANNEL = 0
LED_STRIP = ws.WS2811_STRIP_GRB

# 初始化硬件
sockid = lirc.init("lifetec", blocking=False)
strip = Adafruit_NeoPixel(LEDS, PIN, 800000, 10, False, BRIGHTNESS, LED_CHANNEL, LED_STRIP)
strip.begin()

def start_screensaver():
    global screensaver_process
    print("启动屏保...")
    screensaver_process = Popen(["python", "strandtest.py"], start_new_session=True)

def stop_screensaver():
    global screensaver_process
    if screensaver_process is not None:
        try:
            pgid = os.getpgid(screensaver_process.pid)
            os.killpg(pgid, signal.SIGTERM)
            screensaver_process.wait()
            print("终止屏保")
        except ProcessLookupError:
            print("屏保进程已结束")
        screensaver_process = None

# 主循环
while True:
    # 检测遥控器输入
    code = lirc.nextcode()
    if code:
        last_input_time = time.time()
        if screen_saver_running:
            stop_screensaver()
            screen_saver_running = False
        # 处理菜单逻辑:比如根据code执行不同操作...
    
    # 触发屏保逻辑
    if not screen_saver_running and (time.time() - last_input_time) > 5:
        start_screensaver()
        screen_saver_running = True
    
    time.sleep(0.1)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:16:05