首页 > 编程问答 >如何杀死顽固的进程?

如何杀死顽固的进程?

时间:2024-07-22 09:15:14浏览次数:14  
标签:python windows process buffer stdin

我用Python做了一个服务器。

import logging
from Server import Server

logging.basicConfig(
    filename='app.log',             # Log file name
    filemode='w',                   # Append mode ('w' for overwrite)
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',  # Log format
    datefmt='%Y-%m-%d %H:%M:%S',    # Date format
    level=logging.INFO             # Logging level
)

logger = logging.getLogger(__name__)


def main():
    logger.info('starting server...')

    server = Server()
    server.run()


if __name__ == '__main__':
    main()

from threading import Thread, Condition, Timer, Lock, Semaphore, Event
import sys
import logging

logger = logging.getLogger(__name__)


class Server:
    def __init__(self):
        self.istream = sys.stdin.buffer
        self.ostream = sys.stdout.buffer

        self.requests = []
        self.requestsLock = Lock()
        self.mainSem = Semaphore(0)
        self.writeSem = Semaphore(0)
        self.blockEvent = Event()

        self.createThreads()

        self.w = None
        self.r = None

        logger.info('Server initialized')

    def readThread(self):
        while True:
            buffer = self.istream.read()
            logger.info(f'readThread: {buffer}')

            # next: do something with the buffer like extract the request and add it to the requests list

    def writeThread(self):
        while True:
            self.writeSem.acquire()
            logger.info(f'writeThread: {self.requests}')

    def createThreads(self):
        self.r = Thread(target=self.readThread)
        self.w = Thread(target=self.writeThread)

        self.r.start()
        self.w.start()

    def blockCallback(self):
        self.blockEvent.set()

    def run(self):
        while True:
            self.mainSem.acquire()
            print(f'run: {self.requests}')


if __name__ == '__main__':
    server = Server()

运行 python.exe main.py 后,当我在windows中按Ctrl + C时,日志是:

2024-07-22 08:35:14 - __main__ - INFO - starting server...
2024-07-22 08:35:14 - Server - INFO - Server initialized
2024-07-22 08:35:22 - Server - INFO - readThread: b''
2024-07-22 08:35:22 - Server - INFO - readThread: b''
2024-07-22 08:35:22 - Server - INFO - readThread: b''
2024-07-22 08:35:22 - Server - INFO - readThread: b''
2024-07-22 08:35:22 - Server - INFO - readThread: b''
2024-07-22 08:35:23 - Server - INFO - readThread: b''

是stdin(buffer)劫持信号,但我不确定。对此不太熟悉。 那么,发生了什么以及如何终止这个进程?

======================================== =============================================== 更多:

当使用 pyinstaller 制作.exe应用程序时,也不能杀死内部的python进程。 读取线程陷入死循环。

pyinstaller --onefile --name simplified-server --paths ./ .\main.py

使用nodejs生成运行:

在此处输入图像描述

按Ctrl + C: 在此处输入图像描述

生成代码:

const { spawn } = require("child_process");
const { resolve } = require("path");

// const child = spawn("python", [resolve(__dirname, "programs/main.py")], {
//   argv0: "stubborn-child-process",
// });

child = spawn(resolve(__dirname, "dist/simplified-server.exe"));

process.on("exit", () => {
  console.log("Process exited");
});

process.on("SIGINT", () => {
  console.log(arguments);
  console.log("SIGINT received");

  console.log(child.killed);

  child.kill("SIGINT");

  console.log(child.killed);
  process.exit();
});

我不是熟悉带有 stdin 缓冲区块的 .exe 进程和 python 进程。


你说的对,问题出在 sys.stdin.buffer.read() 阻塞了你的读取线程,导致它无法响应 SIGINT 信号(也就是 Ctrl+C)。 当程序收到 SIGINT 信号时,它只会尝试退出主线程,但读取线程仍然卡在 read() 调用中。

为了解决这个问题,你可以尝试以下几种方法:

1. 使用非阻塞读取

不要使用阻塞的 read() 方法,而是使用非阻塞的读取方式,例如:

  • 使用 os.read() 并设置非阻塞标志:
import os

# ...

def readThread(self):
    # 将标准输入设置为非阻塞模式
    os.set_blocking(sys.stdin.fileno(), False)

    while True:
        try:
            # 尝试读取数据,如果没有数据可用,则抛出 BlockingIOError 异常
            buffer = os.read(sys.stdin.fileno(), 1024)  # 读取最多 1024 字节
            if buffer:
                logger.info(f'readThread: {buffer}')

                # 处理读取到的数据...

        except BlockingIOError:
            # 没有数据可读,可以进行其他操作,例如检查事件或休眠一段时间
            time.sleep(0.1) 
  • 使用 select 模块:
import select

# ...

def readThread(self):
    while True:
        # 检查 stdin 是否可读
        readable, _, _ = select.select([sys.stdin], [], [], 0.1)
        if sys.stdin in readable:
            buffer = self.istream.read()
            logger.info(f'readThread: {buffer}')

            # 处理读取到的数据...

2. 使用信号处理

你可以在读取线程中捕获 SIGINT 信号,并在收到信号时退出循环。

import signal

# ...

def readThread(self):
    # 定义信号处理函数
    def signal_handler(sig, frame):
        logger.info('Received SIGINT, exiting readThread...')
        exit(0)

    # 设置信号处理函数
    signal.signal(signal.SIGINT, signal_handler)

    while True:
        # ... 你的读取逻辑 ...

3. 在主线程中关闭 stdin

你可以在主线程中捕获 KeyboardInterrupt 异常(由 Ctrl+C 触发),并在退出程序之前关闭 sys.stdin ,这将导致 read() 方法抛出异常并退出。

def main():
    logger.info('starting server...')

    server = Server()
    try:
        server.run()
    except KeyboardInterrupt:
        logger.info('KeyboardInterrupt received, exiting...')
        sys.stdin.close()

# ...

关于 PyInstaller

当使用 PyInstaller 打包成 .exe 后,信号处理可能会更加复杂。 你可以尝试以下方法:

  • 使用 --console 选项: 将 PyInstaller 的 --console 选项添加到你的命令中,这将创建一个控制台窗口,可以更可靠地接收信号。
  • 使用 pyinstaller-hooks-contrib : 这个第三方库提供了一些钩子,可以帮助 PyInstaller 正确处理信号。

希望这些方法可以帮助你解决问题!

标签:python,windows,process,buffer,stdin
From: 78776655

相关文章

  • 一天一点点,第四天Python基础
    第一天:一天一点点。Python基础-CSDN博客第二天:一天一点点,接上章Python基础-CSDN博客第三天:一天一点点,第三天Python基础(循环语句)-CSDN博客推导式推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。推导式是一种强大且简洁的语法,适用于生......
  • Python - for循环不使用正则表达式附加数组
    以下代码从URL获取版本号,然后对于每个版本号,转到该版本号的页面并使用文件名的特定模式填充数组。生成的数组应包含每个版本号的文件名列表,但它似乎只包含早期版本(2.6)。使用print语句,我可以看到代码的工作原理是它获取sha256sums.asc文件-所有这些文件,所有版本。我猜......
  • 使用 callable_iterator (re.finditer) 导致 Python 冻结
    我有一个为文本的每一行调用的函数。deftokenize_line(line:str,cmd=''):matches=re.finditer(Patterns.SUPPORTED_TOKENS,line)tokens_found,not_found,start_idx=[],[],0print(matches)formatchinmatches:pass#Rest......
  • Python 的 time.sleep - 永远不会醒来
    我认为这将是那些简单的问题之一,但它让我感到困惑。[停止媒体:我是对的。找到了解决方案。查看答案。]我正在使用Python的单元测试框架来测试多线程应用程序。很好而且很直接-我有5个左右的工作线程监视一个公共队列,以及一个为它们制作工作项的生产者线程......
  • python中使用mitmproxy的http模块出错
    我有一个使用mitmproxyhttp函数的代码,它在这里惨败:defmain(stdscr):try:parser=argparse.ArgumentParser(description='NetSourNetworkAnalyzer')parser.add_argument('--proxy',action='store_true',help='EnableH......
  • 使用python图像去噪没有获得所需的重建图像
    我是python机器学习的初学者,我正在编写一个程序,使图像变得嘈杂,然后我的程序输出重建的图像。我正在使用加性高斯白噪声并使用前馈神经网络。我的程序显示真实图像、噪声图像和重建图像。这些是我通常得到的结果。有人知道如何解决这样的问题吗?这是我的代码:ap......
  • 使用 pip 22.3.1 和 python 3.11.0 安装 MetaTrader5 错误
    我正在尝试使用pip在Windows上安装MetaTrader5。python--versionPython3.11.0pip--versionpip22.3.1pipinstallMetaTrader5ERROR:CouldnotfindaversionthatsatisfiestherequirementMetaTrader5(fromversions:none)ERROR:Nomatchingdistribu......
  • 在 Python 中溶解线条
    我有一个包含多行的形状文件。我正在寻找一种方法来消除所有的接触线。这在ArcMap中是可能的,但似乎在Python和QGIS中都无法做到:之前:所需的输出:这需要在多行上完成,因此像QGIS合并一样手动执行不是一个选项。在ArcMap中,我曾经使用“溶解”......
  • 一个简单的问题(python、串行通信和arduinos)
    只是一个关于小脚本的快速问题,由于某种原因无法工作我运行了这个脚本:importserialimporttimeimportturtledefserialreading():serialPort=serial.Serial(port="COM5",baudrate=9600,bytesize=8,timeout=2,stopbits=serial.STOPBITS_ONE......
  • 我在 Windows 10 上运行 Python 代码后控制台立​​即关闭
    虽然我在代码末尾使用input(),但在Windows10(IDLE之外)的窗口中输入名称后,控制台仍然立即关闭,并且我看不到结果。我该怎么做才能阻止控制台关闭?#!python3name=input('Enteryourname:')print('Hello'+name)input('pressEntertoexit:')你在代码末尾......