문제

Wxpython에서 GUI 애플리케이션 작업을하고 있으며, 기계에서 언제든지 내 응용 프로그램 사본 만 실행 중인지 확인할 수있는 방법을 잘 모르겠습니다. 응용 프로그램의 특성으로 인해 두 번 이상 실행되는 것은 의미가 없으며 빠르게 실패합니다. Win32에서는 단순히 이름이 지정된 Mutex를 만들고 시작시 확인할 수 있습니다. 불행히도, 나는이를 수행 할 수있는 Linux의 어떤 시설도 모른다.

응용 프로그램이 예기치 않게 충돌하면 자동으로 출시 될 무언가를 찾고 있습니다. 충돌하여 잠금 파일을 수동으로 삭제 해야하는 경우 사용자에게 부담을주지 않아도됩니다.

도움이 되었습니까?

해결책

세마포어 사용을 포함하여 몇 가지 일반적인 기술이 있습니다. 내가 가장 자주 사용하는 것은 시작 과정의 PID가 포함 된 시작시 "PID 잠금 파일"을 만드는 것입니다. 프로그램이 시작될 때 파일이 이미 존재하는 경우, 그것을 열고 PID를 내부로 잡고, 해당 PID가 실행중인 프로세스가 실행 중인지 확인하십시오.PID 프로그램 인스턴스인지 확인하려면 종료 된 경우 PID로 파일을 덮어 씁니다. PID 파일의 일반적인 이름은 다음과 같습니다 application_name.pid.

다른 팁

올바른 것은 사용을 사용하는 자문 잠금입니다 flock(LOCK_EX); 파이썬에서는 이것이 발견됩니다 fcntl 기준 치수.

pidfiles와 달리, 이러한 잠금은 어떤 이유로 든 프로세스가 사망 할 때 항상 자동으로 해제되며 파일 삭제와 관련된 경주 조건이 없습니다 (파일이 그렇지 않으므로 필요 잠금을 해제하도록 삭제하려면), PID를 상속하는 다른 프로세스가있을 가능성이 없어서 오래된 잠금을 검증하는 것처럼 보일 가능성이 없습니다.

부정한 셧다운 감지를 원한다면 잠금 장치를 잡은 후 파일에 마커 (PID 등)를 파일에 작성한 다음 깨끗한 셧다운 (잠금 장치가 고정되어있는 동안 파일)을 0 바이트 상태로 자울 수 있습니다. ); 따라서 잠금 장치가 유지되지 않고 파일이 비어 있지 않으면 부정한 종료가 표시됩니다.

The를 사용하여 완전한 잠금 솔루션 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)

wxwidgets는이 목적을 위해 WXSingleInstanCechecker 클래스를 제공합니다. wxpython doc, 또는 wxwidgets doc. WXWIDGETS DOC에는 C ++의 샘플 코드가 있지만 파이썬은 다음과 같은 것이어야합니다.

  name = "MyApp-%s" % wx.GetUserId()
  checker = wx.SingleInstanceChecker(name)
  if checker.IsAnotherRunning():
      return False

이것은 대답 사용자에 의해 Zgoda. 주로 잠금 파일에 대한 쓰기 액세스와 관련된 까다로운 우려 사항을 해결합니다. 특히 잠금 파일이 처음으로 생성 된 경우 root, 다른 사용자 foo 그런 다음 사용자에 대한 쓰기 권한이 없기 때문에이 파일을 다시 작성하려고 시도 할 수 없습니다. foo. 명백한 해결책은 모든 사람을위한 쓰기 권한으로 파일을 만드는 것 같습니다. 이 솔루션은 또한 다른 것들을 기반으로합니다 대답 나에 의해, 그러한 사용자 정의 권한이있는 파일을 만들어야합니다. 이 문제는 귀하의 프로그램을 포함한 모든 사용자가 프로그램을 운영 할 수있는 현실 세계에서 중요합니다. root.

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 권한. 어떤 디렉토리를 사용할 디렉토리를 결정할 수 있습니다.

잠금 파일에 파일 핸들을 열 필요가 없습니다.

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)

UNIX의 SYSV 세마포어로 인터페이스하는 파이썬 모듈을 찾으십시오. 세마포어에는 SEM_UNDO 플래그가있어 프로세스가 충돌하면 프로세스에서 보유한 리소스가 릴리스됩니다.

그렇지 않으면 Bernard가 제안한 것처럼 사용할 수 있습니다

import os
os.getpid()

그리고/var/run/에 작성하십시오.application_name.PID. 프로세스가 시작되면/var/run/의 PID가 있는지 확인해야합니다.application_name.PID는 PS 테이블에 나열되어 있고 그럴 경우 종료합니다. 그렇지 않으면 자체 PID를/var/run/에 작성하십시오.application_name.PID. 다음 var_run_pid에는/var/run/에서 읽은 PID가 있습니다.application_name.PID

cmd = "ps -p %s -o comm=" % var_run_pid
app_name = os.popen(cmd).read().strip()
if len(app_name) > 0:
    Already running

정의 된 함수 세트 semaphore.h -- sem_open(), sem_trywait(), 등 - POSIX는 동일하다고 생각합니다.

잠금 파일을 생성하고 PID를 넣으면 프로세스 ID를 확인하고 충돌했는지 알 수 있습니까?

나는 개인적으로 이것을하지 않았으므로 적절한 양의 소금을 가지고 가져 가십시오. :피

'PIDOF'유틸리티를 사용할 수 있습니까? 앱이 실행중인 경우 PIDOF는 앱의 프로세스 ID를 stdout에 작성합니다. 그렇지 않은 경우 Newline (LF)을 인쇄하고 오류 코드를 반환합니다.

예제 (Bash, Simplicity) :

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#

지금까지 가장 일반적인 방법은 파일을/var/run/wall [application] .pid로 삭제하는 것입니다. 대안으로 동일한 디렉토리에 이름이 지정된 파이프를 만들어 새 파일을 열기 위해 활성 프로세스로 메시지를 보낼 수 있습니다.

후속 시도 된 인스턴스의 명령 줄 인수를 첫 번째 인스턴스에 전달할 수 있기를 원할 때 이러한 종류의 응용 프로그램을 실행하기위한 기본 프레임 워크를 만들었습니다. 인스턴스가 이미 듣고있는 인스턴스를 찾지 못하면 사전 정의 된 포트에서 듣기 시작합니다. 인스턴스가 이미 존재하면 소켓을 통해 명령 줄 인수를 보냅니다.

설명이있는 코드

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top