33

WxPython で GUI アプリケーションを作成していますが、マシン上でアプリケーションのコピーが常に 1 つしか実行されないようにする方法がわかりません。アプリケーションの性質上、複数回実行しても意味がなく、すぐに失敗します。Win32 では、名前付きミューテックスを作成して起動時に確認するだけです。残念ながら、これを実行できる Linux の機能を私は知りません。

アプリケーションが予期せずクラッシュした場合に自動的に解放されるものを探しています。クラッシュしたために手動でロック ファイルを削除する必要があり、ユーザーに負担をかけたくありません。

4

12 に答える 12

61

flock(LOCK_EX)正しいことは、;を使用したアドバイザリ ロックです。Python では、これはfcntlモジュールにあります。

pidfiles とは異なり、これらのロックは、何らかの理由でプロセスが終了したときに常に自動的に解放され、ファイルの削除に関連する競合状態が存在せず (ロックを解放するためにファイルを削除する必要がないため)、別の可能性はありません。プロセスは PID を継承し、古いロックを検証しているように見えます。

不正なシャットダウンの検出が必要な場合は、ロックを取得した後にマーカー (伝統主義者の場合は PID など) をファイルに書き込み、クリーンなシャットダウンの前にファイルを 0 バイトの状態に切り詰めることができます (ロックが保持されている間)。 ); したがって、ロックが保持されておらず、ファイルが空でない場合は、クリーンでないシャットダウンが示されます。

于 2008-10-21T03:43:36.793 に答える
31

fcntlモジュールを使用した完全なロック ソリューション:

import fcntl
pid_file = 'program.pid'
fp = open(pid_file, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    # another instance is running
    sys.exit(1)
于 2008-10-21T08:30:11.147 に答える
25

セマフォの使用など、いくつかの一般的な手法があります。最も頻繁に使用されるのは、実行中のプロセスの pid を含む「pid ロック ファイル」を起動時に作成することです。プログラムの起動時にファイルが既に存在する場合は、ファイルを開いて内部の pid を取得し、その pid を持つプロセスが実行されているかどうかを確認します。実行されている場合は、/proc/ pidの cmdline 値を確認して、その後終了する場合は、プログラムのインスタンスを削除します。そうでない場合は、ファイルを pid で上書きします。pid ファイルの通常の名前はapplication_name です.pid

于 2008-10-21T02:10:24.143 に答える
8

wxWidgets は、この目的のために wxSingleInstanceChecker クラスを提供します: wxPython docまたはwxWidgets doc。wxWidgets doc には C++ のサンプル コードがありますが、同等の Python は次のようになります (未テスト):

  name = "MyApp-%s" % wx.GetUserId()
  checker = wx.SingleInstanceChecker(name)
  if checker.IsAnotherRunning():
      return False
于 2009-01-24T15:20:51.833 に答える
6

これは、ユーザーzgodaによる回答に基づいています。これは主に、ロック ファイルへの書き込みアクセスに関係する厄介な問題に対処します。特に、ロック ファイルが最初に によって作成された場合、ユーザー の書き込み権限がないため、別のユーザーがこのファイルを正常に書き換えることができなくなります。明らかな解決策は、全員の書き込み権限を持つファイルを作成することです。このソリューションは、私による別の回答にも基づいており、そのようなカスタム権限でファイルを作成する必要があります。この懸念は、プログラムが を含む任意のユーザーによって実行される可能性がある現実の世界では重要です。rootfoofooroot

import fcntl, os, stat, tempfile

app_name = 'myapp'  # <-- Customize this value

# Establish lock file settings
lf_name = '.{}.lock'.format(app_name)
lf_path = os.path.join(tempfile.gettempdir(), lf_name)
lf_flags = os.O_WRONLY | os.O_CREAT
lf_mode = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH  # This is 0o222, i.e. 146

# Create lock file
# Regarding umask, see https://stackoverflow.com/a/15015748/832230
umask_original = os.umask(0)
try:
    lf_fd = os.open(lf_path, lf_flags, lf_mode)
finally:
    os.umask(umask_original)

# Try locking the file
try:
    fcntl.lockf(lf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    msg = ('Error: {} may already be running. Only one instance of it '
           'can run at a time.'
           ).format('appname')
    exit(msg)

上記のコードの制限は、予期しないアクセス許可を持つロック ファイルが既に存在する場合、それらのアクセス許可が修正されないことです。

ロック ファイルのディレクトリとして使用/var/run/<appname>/したかったのですが、このディレクトリを作成するにはroot権限が必要です。どのディレクトリを使用するかは、自分で決めることができます。

ロック ファイルへのファイル ハンドルを開く必要がないことに注意してください。

于 2013-02-22T04:18:27.207 に答える
4

TCP ポートベースのソリューションは次のとおりです。

# Use a listening socket as a mutex against multiple invocations
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 5080))
s.listen(1)
于 2016-01-07T16:04:31.957 に答える
1

UNIX 上の SYSV セマフォに接続する python モジュールを探してください。セマフォには SEM_UNDO フラグがあり、プロセスがクラッシュした場合にプロセスによって保持されているリソースが解放されます。

それ以外の場合は、バーナードが提案したように、使用できます

import os
os.getpid()

そして、それを /var/run/ application_name .pid に書き込みます。プロセスが開始すると、/var/run/ application_name .pid の pid が ps テーブルにリストされているかどうかを確認し、リストされている場合は終了します。そうでない場合は、独自の pid を /var/run/ application_name .pid に書き込みます。次の var_run_pid は、 /var/run/ application_name .pidから読み取った pid です。

cmd = "ps -p %s -o comm=" % var_run_pid
app_name = os.popen(cmd).read().strip()
if len(app_name) > 0:
    Already running
于 2008-10-21T02:39:56.533 に答える
1

semaphore.h-- sem_open()、など -- で定義されている一連の関数sem_trywait()は、POSIX に相当すると思います。

于 2008-10-21T02:10:53.550 に答える
0

ロック ファイルを作成してその中に pid を入れると、プロセス ID をチェックして、クラッシュしたかどうかがわかります。

私はこれを個人的に行っていないので、適切な量の塩で服用してください. :p

于 2008-10-21T02:08:17.953 に答える
0

「pidof」ユーティリティを使用できますか? アプリが実行中の場合、pidof はアプリのプロセス ID を stdout に書き込みます。そうでない場合は、改行 (LF) を出力し、エラー コードを返します。

例 (簡単にするために bash から):

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#
于 2008-10-21T02:09:29.027 に答える
0

最も一般的な方法は、実行中のプロセスまたは親プロセスの PID のみを含む [application].pid というファイルを /var/run/ にドロップすることです。別の方法として、同じディレクトリに名前付きパイプを作成して、アクティブなプロセスにメッセージを送信できるようにすることもできます。たとえば、新しいファイルを開くことができます。

于 2008-10-21T02:10:09.963 に答える