在给定时间后终止从APScheduler启动的线程

0 投票
1 回答
1598 浏览
提问于 2025-04-18 07:31

我遇到的问题是:用户需要在一天中的特定时间通过远程桌面登录到Windows服务器。我有一段可以工作的代码,但我觉得线程没有正确关闭,因为过了一段时间后,程序就停止了。

我想关闭这个由AP Scheduler启动的线程,有人能告诉我该怎么正确地做到这一点吗?我试过使用线程的join方法和退出方法,还有._Exit(),但都没有效果(或者说本来就不应该有效),我现在很困惑。

import sys
import os
import subprocess
import signal
import time
from apscheduler.scheduler import Scheduler
from pykeyboard import PyKeyboard
from threading import Thread

def rdp_start():
    os.system('rdesktop -d domain -u username -p password -g 1600x1050 -a 16 123.123.123.123')

def rdp_check():
    p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
    out, err = p.communicate()
    for line in out.splitlines():
        if 'rdesktop' in str(line):
            print("Rdesktop is running!")
    else:
        print("Starting rdesktop!")
        rdp_job = Thread(target = rdp_start, args = ())
        rdp_job.start()
        time.sleep(5)
        k = PyKeyboard()
        k.tap_key(k.enter_key)
        #time.sleep(600)
        #Where I would like to kill rdp_job, and remove rdp_kill scheduling

def rdp_kill():
    p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
    out, err = p.communicate()
    for line in out.splitlines():
        if 'rdesktop' in str(line):
            pid = int(line.split(None, 1)[0])
            os.kill(pid, signal.SIGKILL)
    print("Killed RDP")

def idle():
    # Stop from sleepin
    k = PyKeyboard()
    k.tap_key(k.scroll_lock_key)
    k.tap_key(k.scroll_lock_key)

sched = Scheduler()
sched.daemonic = False
sched.start()

# Fix screen issues with PyUserInput
os.system('xhost + > /etc/null')

sched.add_cron_job(rdp_check, hour=15)
sched.add_cron_job(rdp_kill, hour=15, minute=8)
sched.add_cron_job(rdp_check, hour=23)
sched.add_cron_job(rdp_kill, hour=23, minute=8)
sched.add_cron_job(rdp_check, hour=7)
sched.add_cron_job(rdp_kill, hour=7, minute=8)
sched.add_cron_job(idle, second='*/60')

我知道强行结束线程通常是不好的做法,但我真的需要这个程序能够运行任意时间,有人能给我指个方向吗?

1 个回答

0

如果你在使用Linux系统,可以考虑以下几点:

1) 不要使用 Thread,可以直接在后台运行 rdesktop 命令:

os.system('rdesktop ... &')

2) killall 命令可以找到正在运行的程序,并可以选择性地给它们发送信号。

要检查 rdesktop 命令是否在运行,可以给它发送信号 #0。如果找到了进程,它会返回状态 0;如果没有找到,则返回大于 0 的状态:

$ killall -0 sleep
$ echo $?
0
$ killall -0 beer
beer: no process found

3) 如果要结束 rdesktop 进程:

os.system('killall rdesktop')

注意,上面的内容假设你最多只有一个 rdesktop 进程在运行,并且是你自己启动的,这样你才能用 killall -0 来检查它。

撰写回答