简体   繁体   中英

How to wait after process kill until the file is unlocked on Windows using Python?

Problem description

I have a unittest that calls an external program and does some testing. After that, the external process is killed, and the test tries to clean up files the external program created. However, if I just call unlink() directly after the kill() command on Windows 10, I get:

PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'my.log'

If I time.sleep(4) before calling unlink() everything works as expected. The 4 was chosen arbitrarily, other times also work.

MCVE

This MCVE has two files. A server.py that simply locks a logging file and a test_client.py that calls the server, kills it and finally tries to remove the logging file.

test_client.py

import pathlib
import subprocess
import sys
import time

# Create test folder
server_path = pathlib.Path('.')
server_path.mkdir(exist_ok=True)

server_file = pathlib.Path('server.py').resolve()

# Start server in test folder
proc = subprocess.Popen([sys.executable, str(server_file)], cwd=server_path)

time.sleep(4)

# Kill server
proc.kill()

# Activate the following line to avoid the PermissionError: [WinError 32] ...
#time.sleep(4)

# Clean up
pathlib.Path('my.log').unlink()

server.py

import time
import logging

logging.basicConfig(
    filename='my.log',
    level=logging.DEBUG)

logging.info('I just started my work')

while True:
    time.sleep(1)

Question

  • Is there a way to wait for the kill to be finished?
  • Bonus if code is not platform specific

The correct way is

# Kill server
proc.kill()

# Activate the following line to avoid the PermissionError: [WinError 32] ...
proc.communicate()

# Clean up
pathlib.Path('my.log').unlink()

The reason why it behaves like this require some documentation.

As stated in Python Official Documentation ,

Popen.kill() Kills the child. On Posix OSs the function sends SIGKILL to the child. On Windows kill() is an alias for terminate().

Popen.terminate() Stop the child. On Posix OSs the method sends SIGTERM to the child. On Windows the Win32 API function TerminateProcess() is called to stop the child.

In windows, as stated, it is calling TerminateProcess function on Win32 API. While, it is clearly stated that

TerminateProcess is asynchronous ; it initiates termination and returns immediately. If you need to be sure the process has terminated, call the WaitForSingleObject function with a handle to the process.

Therefore, kill() is just simply "Ask for stop". Not stopped yet. Thus, you need a method for 'waiting' the process end.

communicate() is designed for this purpose too, as still stated in doc

Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM