Pythonで特定のpidを持つプロセスが存在するかどうかを確認するにはどうすればよいですか?


109

pidが有効なプロセスに対応しているかどうかを確認する方法はありますか?from以外の別のソースからpidを取得os.getpid()しています。そのpidを持つプロセスがマシンに存在しないかどうかを確認する必要があります。

UnixとWindowsで利用できるようにする必要があります。また、PIDが使用されていないかどうかを確認しています。


2
Windowsは非標準のOSです。これらの種類のものは移植できません。あなたは両方を持つことができないことを知っています、それがあなたの優先事項ですか?優先度として1つを選択し、質問を編集します。
S.Lott

26
@ S.Lott Windowsは非標準のOSですこれは私がSOで見た中で最もばかげた発言の1つです...
Piotr Dobrogost

2
@Piotr Dobrogost:POSIX標準のunixおよび非POSIX標準のWindowsを処理するコードを提供できますか?その場合は、(a)問題を解決し、(b)Windowsがなんらかの方法でPOSIX標準に準拠していることを明確にしてください。
S.Lott、2013

3
@PiotrDobrogost S.Lottの発言は、市場シェアよりも実装の詳細とAPIサポートについてだったと思います。
ロイ・ティンカー

3
Windowsは他の一般的なOSとの共通点が他のOSとの共通点よりも確かに少なくなっています。(Web開発を行う人なら誰でも、同様に悪名高いMicrosoft製品に例えるかもしれません。)しかし、@ S.Lottへの反応:Linux、OSX、BSDなどでも動作しないはずのWindows用のPythonコードを書くことはめったにないので、特にPythonはプラットフォームの違いを可能な限り抽象化するので、「優先して選択する」ことは正直な助言だとは思わないでください。
Michael Scheper

回答:


162

pidにシグナル0を送信すると、pidが実行されていない場合はOSError例外が発生し、それ以外の場合は何も実行されません。

import os

def check_pid(pid):        
    """ Check For the existence of a unix pid. """
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

3
LinuxとOSXで確実に機能します。Windowsについて話すことはできません。要求しているという意味ではプロセスを強制終了しません。シグナル0を送信します。これは基本的に「実行中ですか?」です。
mluebke 2009

10
これは、UNIX風のシグナルなどがないため、Windowsでは確実に機能しません。
Alexander Lebedev

13
完了するには、エラー番号が3であることを確認する必要もあります(例外をキャッチして、最初の引数を確認します)。ターゲットプロセスは存在するが、何らかの理由でシグナルを送信する権限がない場合、これは重要です。
haridsv 2010

8
現在、Windowsでサポートされています。docs.python.org/library/os.html?highlight=os.kill#os.kill
マイケル

15
os.killはWindowsでサポートされていますが、プロセスを終了する(または失敗する)場合os.kill(pid, 0)と同じos.kill(pid, signal.CTRL_C_EVENT)です。これをサブプロセスで試したOSErrorところ、どこerrno==EINVALにあるのかがわかります。
ジェイソンR.クームス

76

psutilモジュールを見てください:

psutil(pythonシステムおよびプロセスユーティリティ)は、Pythonで実行中のプロセスおよびシステム使用率(CPU、メモリ、ディスク、ネットワーク)に関する情報を取得するためのクロスプラットフォームライブラリです。[...]現在、LinuxWindowsOSXFreeBSDSun Solarisの32ビット64 ビットの両方のアーキテクチャをサポートしており、Pythonバージョンは2.6から3.4です(Python 2.4および2.5のユーザーは2.1.3バージョンを使用できます)。 。PyPyも動作することが知られています。

これにはpid_exists()、指定されたpidのプロセスが存在するかどうかを確認するために使用できるという関数があります。

次に例を示します。

import psutil
pid = 12345
if psutil.pid_exists(pid):
    print("a process with pid %d exists" % pid)
else:
    print("a process with pid %d does not exist" % pid)

参考のため:



Windowsでpid_existsの信頼性が停止することがありました。死んだPIDが使用中であると誤って報告されていました。これは、特にOSのアップグレードを行うときに、psutilモジュールを時々更新しておくための注意です。
デイモンブロディ2018

62

mluebkeコードは100%正しくありません。kill()は、EPERM(アクセス拒否)を発生させることもできます。その場合、明らかにプロセスが存在することを意味します。これは動作するはずです:

(Jason R. Coombsのコメントに従って編集)

import errno
import os

def pid_exists(pid):
    """Check whether pid exists in the current process table.
    UNIX only.
    """
    if pid < 0:
        return False
    if pid == 0:
        # According to "man 2 kill" PID 0 refers to every process
        # in the process group of the calling process.
        # On certain systems 0 is a valid PID but we have no way
        # to know that in a portable fashion.
        raise ValueError('invalid PID 0')
    try:
        os.kill(pid, 0)
    except OSError as err:
        if err.errno == errno.ESRCH:
            # ESRCH == No such process
            return False
        elif err.errno == errno.EPERM:
            # EPERM clearly means there's a process to deny access to
            return True
        else:
            # According to "man 2 kill" possible error values are
            # (EINVAL, EPERM, ESRCH)
            raise
    else:
        return True

pywin32、ctypes、またはC拡張モジュールを使用しない限り、Windowsでこれを行うことはできません。外部libに依存することに問題がなければ、psutilを使用できます。

>>> import psutil
>>> psutil.pid_exists(2353)
True

haridsvは、テストがe.errno!= 3であることを示唆しています。おそらくe.errno!= errno.ESRCH
Jason R. Coombs

どうして?ESRCHは「そのようなプロセスはありません」を意味します。
GiampaoloRodolà

2
正しい。ESRCHは「そのようなプロセスがない」ことを意味するため、errno!= ESRCHは「そのようなプロセスがない」または「プロセスが存在しない」ことを意味します。これは、関数の名前とよく似ています。EPERMについて具体的に説明しましたが、他に考えられるエラーコードは何を意味していますか?ESRCHは密接に関連しているように見えますが、チェックの目的に緩やかに関連しているエラーコードを特定することは正しくないようです。
Jason R. Coombs

あなたが正しい。私はあなたが提案したものを反映するようにコードを編集しました。
GiampaoloRodolà2013

python3でos.kill()はProcessLookupErrorをスローします
martinkunev

19

プロセスへの「シグナル0」の送信に関する回答は、問題のプロセスがテストを実行しているユーザーによって所有されている場合にのみ機能します。それ以外の場合は、pidがシステムに存在していても、permissionsOSErrorによりdueを取得します。

この制限を回避するために、/proc/<pid>存在するかどうかを確認できます。

import os

def is_running(pid):
    if os.path.isdir('/proc/{}'.format(pid)):
        return True
    return False

これは、明らかにLinuxベースのシステムにのみ適用されます。


違う。PermissionErrorpidが存在することを意味し、pidが存在ProcessLookupErrorしない場合に取得します。
jfs

OSErrorいずれかのエラー番号を見経由または複数の専門引く経由-拒否された権限によるものが他のものと区別することができますPermissionError/ ProcessLookupErrorから派生した例外をOSError。さらに、プロセスが存在する場合にのみ権限エラーが発生します。したがって、あなたの例はLinuxや他のいくつかのUnicesで機能する代替方法にすぎませんが、適切にを呼び出すよりも完全ではありませんos.kill(pid, 0)
maxschlepzig 2018

このソリューションはcorssプラットフォームではありません。OPは、UnixとWindowsで利用できることを望んでいます。/procprocfsのは、唯一のLinux上ではなく、さらにBSDやOSX上で終了します。
Charles

/ procがマウントされている場合、このメソッドは失敗します。hidepid= 2、プロセスが別のユーザーによって所有されている場合、プロセスはリストに表示されません。
パーキンス

8

Python 3.3以降では、errno定数の代わりに例外名を使用できます。Posixバージョン

import os

def pid_exists(pid): 
    if pid < 0: return False #NOTE: pid == 0 returns True
    try:
        os.kill(pid, 0) 
    except ProcessLookupError: # errno.ESRCH
        return False # No such process
    except PermissionError: # errno.EPERM
        return True # Operation not permitted (i.e., process exists)
    else:
        return True # no error, we can send a signal to the process

7

実行中のプロセスとそのIDの完全なリストを取得するWindows固有の方法については、こちらご覧ください。それは次のようなものになります

from win32com.client import GetObject
def get_proclist():
    WMI = GetObject('winmgmts:')
    processes = WMI.InstancesOf('Win32_Process')
    return [process.Properties_('ProcessID').Value for process in processes]

次に、このリストに対して取得したpidを確認できます。パフォーマンスコストについてはわかりません。pid検証を頻繁に行う場合は、これを確認することをお勧めします。

* NIxの場合は、mluebkeのソリューションを使用します。


これは私にとってはうまくいきました。プロセス名をチェックしたかったので、「ProcessID」を「Name」に交換し、TrueまたはFalseを返すようにリストのチェックに変換しました。
JamesR

6

ntrrgcをベースにして、Windowsのバージョンを強化して、プロセスの終了コードとアクセス許可を確認します。

def pid_exists(pid):
    """Check whether pid exists in the current process table."""
    if os.name == 'posix':
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
    else:
        import ctypes
        kernel32 = ctypes.windll.kernel32
        HANDLE = ctypes.c_void_p
        DWORD = ctypes.c_ulong
        LPDWORD = ctypes.POINTER(DWORD)
        class ExitCodeProcess(ctypes.Structure):
            _fields_ = [ ('hProcess', HANDLE),
                ('lpExitCode', LPDWORD)]

        SYNCHRONIZE = 0x100000
        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if not process:
            return False

        ec = ExitCodeProcess()
        out = kernel32.GetExitCodeProcess(process, ctypes.byref(ec))
        if not out:
            err = kernel32.GetLastError()
            if kernel32.GetLastError() == 5:
                # Access is denied.
                logging.warning("Access is denied to get pid info.")
            kernel32.CloseHandle(process)
            return False
        elif bool(ec.lpExitCode):
            # print ec.lpExitCode.contents
            # There is an exist code, it quit
            kernel32.CloseHandle(process)
            return False
        # No exit code, it's running.
        kernel32.CloseHandle(process)
        return True

実際には、によるとmsdn.microsoft.com/en-us/library/windows/desktop/...GetExistCodeProcess必要とPROCESS_QUERY_INFORMATIONし、PROCESS_QUERY_LIMITED_INFORMATIONアクセス権を。
8

コードが間違っていることに注意してください。GetExitCodeProcessハンドルとポインターを受け取ります。このサンプルでExitCodeProcessは、ポインターのみである必要がある場合、2番目のパラメーターとして構造体を受け取ります。
Fabio Zadrozny

OpenProcessの後、GetLastErrorを確認することをお勧めします。ERROR_ACCESS_DENIEDは、プロセスが存在することを意味します!これを使用した完全な例を次に示します。gist.github.com
ociule

4

GiampaoloRodolàのPOSIXに対する答え私のWindows に対する答えを組み合わせると、次のようになります。

import os
if os.name == 'posix':
    def pid_exists(pid):
        """Check whether pid exists in the current process table."""
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
else:
    def pid_exists(pid):
        import ctypes
        kernel32 = ctypes.windll.kernel32
        SYNCHRONIZE = 0x100000

        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if process != 0:
            kernel32.CloseHandle(process)
            return True
        else:
            return False

Windows 8.1ではWindowsバージョンが機能しません。GetExitCodeProcessアクセスできるかどうかを確認する必要があります。
スピードプレーン2014年

kernel32.OpenProcess単独で使用するだけでは十分ではありません。ここで指摘した「プロセスが最近終了した場合、pidはまだハンドルのために存在してもよいです。」kernel32.OpenProcessゼロ以外の値が返された 場合でもkernel32.GetExitCodeProcess、終了コードを確認する必要があります。
ニャー

2

Windowsでは、次のように実行できます。

import ctypes
PROCESS_QUERY_INFROMATION = 0x1000
def checkPid(pid):
    processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0,pid)
    if processHandle == 0:
        return False
    else:
        ctypes.windll.kernel32.CloseHandle(processHandle)
    return True

まず、このコードでは、pidを指定してプロセスのハンドルを取得しようとします。ハンドルが有効な場合は、プロセスのハンドルを閉じてTrueを返します。それ以外の場合は、Falseを返します。OpenProcessのドキュメント:https ://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx


2

これはLinuxで機能します。たとえば、bansheeが実行されているかどうかを確認する場合などです(bansheeは音楽プレーヤーです)。

import subprocess

def running_process(process):
    "check if process is running. < process > is the name of the process."

    proc = subprocess.Popen(["if pgrep " + process + " >/dev/null 2>&1; then echo 'True'; else echo 'False'; fi"], stdout=subprocess.PIPE, shell=True)

    (Process_Existance, err) = proc.communicate()
    return Process_Existance

# use the function
print running_process("banshee")

この方法は、を使用しos.kill(pid, 0)たり見たりする方法に比べて明らかに劣ってい/proc/{pid}ます。1つのsyscallを実行してコードを子にフォークし、その子でシェルを実行します。シェルは余分なミニシェルスクリプトを解釈し、シェルはpgrepを実行する別の子をフォークし、最後にpgrepが反復し/procます。あなたの答えは投稿された質問には答えません。OPは、PIDを指定してメソッドを要求しました。メソッドにはプロセス名が必要です。
maxschlepzig 2018

-2

私はあなたがそれを取得している目的のためにPIDを使用し、エラーを適切に処理すると思います。それ以外の場合、それは古典的なレースです(有効であることを確認したときにPIDが有効である可能性がありますが、後ですぐに消えます)。


私はもっ​​と具体的だったはずです-私は無効性をチェックしています。したがって、基本的には、pidが使用されていないかどうかを確認できるようにしたいと考えています。
エヴァンフォスマルク2009

1
しかし、あなたはその答えで何をしますか?あなたがその知識を得た直後、何かがそのpidを使用するかもしれません。
Damien_The_Unbeliever 2009

@Damien_The_Unbeliever-知識を得た後で何かがそれを使用している場合は問題ありません。競合状態についてあなたが言っていることは理解していますが、私の状況には当てはまらないことを保証できます。
Evan Fosmark 2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.