Bir programın yalnızca tek bir örneğinin çalıştığından emin olun


120

Bir programın yalnızca bir örneğini çalıştırmanın Pythonic yolu var mı?

Bulduğum tek makul çözüm, onu bir bağlantı noktasında bir sunucu olarak çalıştırmaya çalışmak, ardından aynı bağlantı noktasına bağlanmaya çalışan ikinci program - başarısız oluyor. Ama bu gerçekten harika bir fikir değil, belki bundan daha hafif bir şey var mı?

(Programın bazen başarısız olmasının beklendiğini göz önünde bulundurun, yani segfault - böylece "dosyayı kilitle" gibi şeyler çalışmayacaktır)


1
Segfault'u bulup düzeltirseniz belki de hayatınız daha kolay olurdu. Yapması kolay bir şey değil.
David Locke

Kitaplığımda değil, python'un libxml bağlarında ve son derece utangaç - yalnızca birkaç günde bir ateşleniyor.
Slava V

5
Python'un standart kitaplığı, modern UNIX programları için Doğru Şey olan flock () 'u destekler. Bir bağlantı noktasını açmak, çok daha kısıtlı bir ad alanında bir nokta kullanır, oysa pidfiles, onları güvenli bir şekilde geçersiz kılmak için çalışan işlemleri kontrol etmeniz gerektiğinden daha karmaşıktır; sürünün hiçbir sorunu yoktur.
Charles Duffy

s / UNIX / linux / buyrun, FTFY.
kaleissin

Yanıtlar:


101

Aşağıdaki kod işi yapmalıdır, çapraz platformdur ve Python 2.4-3.2 üzerinde çalışır. Windows, OS X ve Linux üzerinde test ettim.

from tendo import singleton
me = singleton.SingleInstance() # will sys.exit(-1) if other instance is running

En son kod sürümü singleton.py olarak mevcuttur . Lütfen hataları buraya kaydedin .

Eğilimi aşağıdaki yöntemlerden birini kullanarak yükleyebilirsiniz:


2
Cevabı güncelledim ve en son sürüme bir bağlantı ekledim. Bir hata bulursanız lütfen github'a gönderin, mümkün olan en kısa sürede çözeceğim.
sorin

2
@Johny_M Teşekkürler, bir yama yaptım ve pypi.python.org/pypi/tendo adresinde
sorin

2
Bu sözdizimi, Python 2.6 altındaki pencerelerde benim için çalışmadı. Benim için işe yarayan şuydu: 1: tendo ithal singleton'dan 2: me = singleton.SingleInstance ()
Brian

25
Bunun kadar önemsiz bir şeye başka bir bağımlılık mı? Pek çekici gelmiyor.
WhyNotHugo

2
Tekil, bir sigterm alan süreçleri işliyor mu (örneğin, bir işlem çok uzun sürüyorsa), yoksa bunu halletmek zorunda mıyım?
JimJty

43

Zgoda tarafından başka bir soruda bulunan basit, çapraz platform çözümü :

import fcntl
import os
import sys

def instance_already_running(label="default"):
    """
    Detect if an an instance with the label is already running, globally
    at the operating system level.

    Using `os.open` ensures that the file pointer won't be closed
    by Python's garbage collector after the function's scope is exited.

    The lock will be released when the program exits, or could be
    released if the file pointer were closed.
    """

    lock_file_pointer = os.open(f"/tmp/instance_{label}.lock", os.O_WRONLY)

    try:
        fcntl.lockf(lock_file_pointer, fcntl.LOCK_EX | fcntl.LOCK_NB)
        already_running = False
    except IOError:
        already_running = True

    return already_running

S.Lott'un önerisine çok benziyor, ancak kodla.


Merak ediyorum: Bu gerçekten çapraz platform mu? Windows'ta çalışıyor mu?
Joachim Sauer

1
fcntlWindows'ta modül yoktur (işlevsellik taklit edilebilir olsa da).
jfs

10
İPUCU: Eğer bunu bir fonksiyona sarmak istiyorsanız 'fp' global olmalıdır, aksi takdirde fonksiyon çıktıktan sonra dosya kapatılacaktır.
cmcginty

1
@Mirko Control + Z bir uygulamadan çıkmaz (bildiğim herhangi bir işletim sisteminde), onu askıya alır. İle uygulama ön plana döndürülebilir fg. Yani, sizin için doğru çalışıyor gibi görünüyor (yani uygulama hala aktif, ancak askıya alınmış, dolayısıyla kilit yerinde kalıyor).
Sam Bull

1
Benim durumumdaki bu kod (Linux'ta Python 3.8.3) modifikasyona ihtiyaç duydu:lock_file_pointer = os.open(lock_path, os.O_WRONLY | os.O_CREAT)
baziorek

30

Bu kod Linux'a özeldir. 'Soyut' UNIX alan soketlerini kullanır, ancak basittir ve eski kilit dosyalarını etrafta bırakmaz. Yukarıdaki çözüme tercih ediyorum çünkü özel olarak ayrılmış bir TCP bağlantı noktası gerektirmiyor.

try:
    import socket
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    ## Create an abstract socket, by prefixing it with null. 
    s.bind( '\0postconnect_gateway_notify_lock') 
except socket.error as e:
    error_code = e.args[0]
    error_string = e.args[1]
    print "Process already running (%d:%s ). Exiting" % ( error_code, error_string) 
    sys.exit (0) 

Benzersiz dize postconnect_gateway_notify_lock, tek bir örneğe zorlanması gereken birden çok programa izin verecek şekilde değiştirilebilir.


1
Roberto, kernel paniğinden veya donanımdan sıfırlamadan sonra \ 0postconnect_gateway_notify_lock dosyasının açılışta mevcut olmayacağından emin misin? Benim durumumda AF_UNIX soket dosyası bundan sonra hala mevcut ve bu tüm fikri yok ediyor. Belirli bir dosya adına kilit edinme ile yukarıdaki çözüm, bu durumda çok güvenilirdir.
Danylo Gurianov

2
Yukarıda belirtildiği gibi, bu çözüm Linux'ta çalışır ancak Mac OS X'te çalışmaz .
Bilal ve Olga

2
Bu çözüm işe yaramıyor. Ubuntu 14.04'te denedim. Aynı komut dosyasını 2 terminal penceresinden aynı anda çalıştırın. İkisi de gayet iyi çalışıyor.
Dimon

1
Bu benim için Ubuntu 16'da çalıştı. Ve süreci herhangi bir şekilde öldürmek, başka birinin başlamasına izin verdi. Dimon Bence testinde yanlış bir şey yaptın. (Belki de yukarıdaki kod çalıştırıldıktan sonra betiğinizi uyutmayı unuttunuz, bu yüzden hemen çıkıp soketten çıktı.)
Luke

1
Bu bir uyku meselesi değil. Kod çalışır ancak yalnızca satır içi kod olarak çalışır. Onu bir işleve koyuyordum. İşlev var olur olmaz yuva kayboluyordu.
Steve Cohen

25

Yeterince piton olup olmadığını bilmiyorum, ancak Java dünyasında tanımlı bir bağlantı noktasında dinleme, tüm büyük platformlarda çalıştığı ve programların çökmesi ile herhangi bir sorunu olmadığı için oldukça yaygın olarak kullanılan bir çözümdür.

Bir bağlantı noktasını dinlemenin diğer bir avantajı, çalışan örneğe bir komut gönderebilmenizdir. Örneğin, kullanıcılar programı ikinci kez başlattığında, çalışan örneğe başka bir pencere açmasını söyleyen bir komut gönderebilirsiniz (örneğin, Firefox bunu yapar. TCP bağlantı noktaları mı yoksa adlandırılmış kanallar mı yoksa bunun gibi bir şey olsa da).


Buna +1, özellikle de çalışan örneği bildirmeme izin verdiği için başka bir pencere oluşturuyor, açılıyor vb.
WhyNotHugo

1
Örneğin kullanın import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.bind(('localhost', DEFINED_PORT)). Bir OSErrorbaşka işlem aynı bağlantı noktasına bağlı olup olmadığını yükseltilecek.
crishoj

13

Daha önce hiç python yazmadım, ancak bu, crond tarafından iki veya daha fazla başlatılmasını önlemek için mycheckpoint'te uyguladığım şey:

import os
import sys
import fcntl
fh=0
def run_once():
    global fh
    fh=open(os.path.realpath(__file__),'r')
    try:
        fcntl.flock(fh,fcntl.LOCK_EX|fcntl.LOCK_NB)
    except:
        os._exit(0)

run_once()

Bunu başka bir sayıda yayınladıktan sonra Slava-N'nin önerisi bulundu (http://stackoverflow.com/questions/2959474). Bu bir işlev olarak adlandırılır, çalıştırılan komut dosyaları dosyasını (bir pid dosyasını değil) kilitler ve komut dosyası bitene kadar (normal veya hata) kilidi korur.


1
Çok zarif. Betiğin argümanlarından yolu alacak şekilde değiştirdim. Ayrıca bunu ortak bir yere yerleştirmenizi önerir - Örnek
Jossef Harush

10

Bir pid dosyası kullanın. Bilinen bir konumunuz var, "/ yol / / pidfile" ve başlangıçta böyle bir şey yapıyorsunuz (kısmen sözde kod, çünkü ben kahve öncesi ve o kadar sıkı çalışmak istemiyorum):

import os, os.path
pidfilePath = """/path/to/pidfile"""
if os.path.exists(pidfilePath):
   pidfile = open(pidfilePath,"r")
   pidString = pidfile.read()
   if <pidString is equal to os.getpid()>:
      # something is real weird
      Sys.exit(BADCODE)
   else:
      <use ps or pidof to see if the process with pid pidString is still running>
      if  <process with pid == 'pidString' is still running>:
          Sys.exit(ALREADAYRUNNING)
      else:
          # the previous server must have crashed
          <log server had crashed>
          <reopen pidfilePath for writing>
          pidfile.write(os.getpid())
else:
    <open pidfilePath for writing>
    pidfile.write(os.getpid())

Yani, başka bir deyişle, bir pidfile olup olmadığını kontrol ediyorsunuz; değilse, pid'nizi bu dosyaya yazın. Pidfile mevcutsa, pid'in çalışan bir sürecin pid'si olup olmadığını kontrol edin; eğer öyleyse, çalışan başka bir canlı işleminiz var, bu yüzden kapatın. Değilse, önceki işlem çöktü, bu yüzden günlüğe kaydedin ve ardından eski dosyanın yerine dosyaya kendi pid'inizi yazın. O halde devam edin.


4
Bunun bir yarış durumu var. Test-sonra-yazma dizisi, iki programın hemen hemen aynı anda başlamasına, dosya bulmamasına ve aynı anda yazmak için açmaya çalışmasına neden olabilir. Bu olmalıdır diğer ilerlemesine izin birinde bir istisna.
S.Lott


5

Bu işe yarayabilir.

  1. Bilinen bir konuma bir PID dosyası oluşturmayı deneyin. Başarısız olursanız, birisi dosyayı kilitler, işiniz biter.

  2. Normal şekilde bitirdiğinizde, PID dosyasını kapatın ve kaldırın, böylece başka biri üzerine yazabilir.

Programınızı, çökse bile PID dosyasını kaldıran bir kabuk betiğine sarabilirsiniz.

Ayrıca, programı askıda kalırsa sonlandırmak için PID dosyasını da kullanabilirsiniz.


3

Kilit dosyası kullanmak, unix'te oldukça yaygın bir yaklaşımdır. Kilitlenirse, manuel olarak temizlemeniz gerekir. PID'yi dosyada saklayabilir ve başlangıçta bu PID ile bir işlem olup olmadığını kontrol edebilir, yoksa kilit dosyasını geçersiz kılabilirsiniz. (Bununla birlikte, dosya oku-kontrol et-pid-yeniden-yazma-dosyasının etrafında bir kilide de ihtiyacınız vardır). Pid'i almak ve kontrol etmek için ihtiyacınız olanı os paketinde bulacaksınız . Belirli bir pid ile bir işlem olup olmadığını kontrol etmenin yaygın yolu, ona ölümcül olmayan bir sinyal göndermektir.

Diğer alternatifler, bunu sürü veya posix semaforları ile birleştirmek olabilir.

Saua'nın önerdiği gibi bir ağ soketi açmak muhtemelen en kolay ve en taşınabilir olanı olacaktır.


3

Uygulamaları için wxPython kullanan herkes için wx.SingleInstanceChecker burada belgelenen işlevi kullanabilirsiniz .

Ben şahsen bir alt sınıfı kullanmak wx.Appkullanımı kılan wx.SingleInstanceCheckerve getiri Falsegelen OnInit()uygulama zaten şöyle yürütme varolan örneği varsa:

import wx

class SingleApp(wx.App):
    """
    class that extends wx.App and only permits a single running instance.
    """

    def OnInit(self):
        """
        wx.App init function that returns False if the app is already running.
        """
        self.name = "SingleApp-%s".format(wx.GetUserId())
        self.instance = wx.SingleInstanceChecker(self.name)
        if self.instance.IsAnotherRunning():
            wx.MessageBox(
                "An instance of the application is already running", 
                "Error", 
                 wx.OK | wx.ICON_WARNING
            )
            return False
        return True

Bu, wx.Appbirden çok örneği yasaklayan basit bir drop-in değişimidir . Basitçe yerine kullanmak için wx.Appbirlikte SingleAppşöyle kodunuzda:

app = SingleApp(redirect=False)
frame = wx.Frame(None, wx.ID_ANY, "Hello World")
frame.Show(True)
app.MainLoop()

Bir singleton için bir soket listeleme iş parçacığını kodladıktan sonra bunu buldum, bu harika çalışıyor ve zaten bir çift programa yükledim, ancak ek "uyandırma" istiyorum, singleton'u verebilirim böylece onu üst üste binen büyük bir pencere yığınının önünde ve ortasında. Ayrıca: "burada belgelenmiştir" bağlantısı, oldukça kullanışsız otomatik oluşturulmuş belgelere işaret ediyor, bu daha iyi bir bağlantıdır
RufusVS

@RufusVS Haklısınız - bu çok daha iyi bir dokümantasyon bağlantısı, cevabı güncellediniz.
Matt Coubrough

3

İşte nihai Windows'a özgü çözümüm. Aşağıdakileri, belki de "onlyone.py" veya her neyse adı verilen bir modüle koyun. Bu modülü doğrudan __ ana __ python komut dosyanıza ekleyin.

import win32event, win32api, winerror, time, sys, os
main_path = os.path.abspath(sys.modules['__main__'].__file__).replace("\\", "/")

first = True
while True:
        mutex = win32event.CreateMutex(None, False, main_path + "_{<paste YOUR GUID HERE>}")
        if win32api.GetLastError() == 0:
            break
        win32api.CloseHandle(mutex)
        if first:
            print "Another instance of %s running, please wait for completion" % main_path
            first = False
        time.sleep(1)

açıklama

Kod, adı komut dosyasının tam yolundan türetilen bir muteks oluşturmaya çalışır. Gerçek dosya sistemiyle olası karışıklığı önlemek için eğik çizgi kullanıyoruz.

Avantajları

  • Yapılandırma veya "sihirli" tanımlayıcılara gerek yok, gerektiği kadar farklı komut dosyasında kullanın.
  • Etrafta eski dosya kalmaz, muteks sizinle birlikte ölür.
  • Beklerken faydalı bir mesaj yazdırır

3

Windows'ta bunun için en iyi çözüm, @zgoda tarafından önerilen muteksleri kullanmaktır.

import win32event
import win32api
from winerror import ERROR_ALREADY_EXISTS

mutex = win32event.CreateMutex(None, False, 'name')
last_error = win32api.GetLastError()

if last_error == ERROR_ALREADY_EXISTS:
   print("App instance already running")

Bazı yanıtlar fctnl(@sorin tendo paketinde de bulunur) kullanır ki bu Windows'ta bulunmaz ve python uygulamanızı pyinstallerstatik içe aktarma gibi bir paket kullanarak dondurmaya çalışırsanız bir hata verir.

Ayrıca, kilit dosyası yöntemini kullanmak read-onlyveritabanı dosyalarında bir sorun yaratır (bu durumla karşılaşılır sqlite3).


2

Bunu bir cevap olarak gönderiyorum çünkü yeni bir kullanıcıyım ve Stack Overflow henüz oy vermeme izin vermiyor.

Sorin Sbarnea'nın çözümü benim için OS X, Linux ve Windows altında çalışıyor ve bunun için minnettarım.

Bununla birlikte, tempfile.gettempdir (), OS X ve Windows altında bir şekilde ve diğer bazı / çok / tümü (?) * Nixler altında (OS X'in de Unix olduğu gerçeğini göz ardı ederek!) Davranır. Fark, bu kod için önemlidir.

OS X ve Windows, kullanıcıya özgü geçici dizinlere sahiptir, bu nedenle bir kullanıcı tarafından oluşturulan bir geçici dosya başka bir kullanıcı tarafından görülmez. Buna karşılık, * nix'in birçok sürümünde (Ubuntu 9, RHEL 5, OpenSolaris 2008 ve FreeBSD 8'i test ettim), temp dizini tüm kullanıcılar için / tmp'dir.

Bu, çok kullanıcılı bir makinede kilit dosyası oluşturulduğunda, / tmp içinde oluşturulduğu ve yalnızca kilit dosyasını ilk kez oluşturan kullanıcının uygulamayı çalıştırabileceği anlamına gelir.

Olası bir çözüm, mevcut kullanıcı adını kilit dosyasının adına yerleştirmektir.

OP'nin bir bağlantı noktasını kapma çözümünün çok kullanıcılı bir makinede de yanlış davranacağını belirtmek gerekir.


Bazı okuyucular için (örneğin ben) istenen davranış, kaç kullanıcının dahil olduğuna bakılmaksızın yalnızca bir kopyanın dönem çalıştırabilmesidir. Böylece, kullanıcı başına tmp dizinleri bozulurken, paylaşılan / tmp veya bağlantı noktası kilidi istenen davranışı sergiler.
Jonathan Hartley

2

Kullandığım single_processbenim gentoo üzerinde;

pip install single_process

örnek :

from single_process import single_process

@single_process
def main():
    print 1

if __name__ == "__main__":
    main()   

bakın: https://pypi.python.org/pypi/single_process/1.0


Py3'te başarısız. Paket yanlış yapılandırılmış görünüyor.
Ekevoo

Windows'ta şunu alıyorum: ImportError: fcntl adında bir modül yok
Andrew W. Phillips

1

Dosya sistemine vurmak zorunda kalmadan, süreç gruplarını kullanan iyi bir POSIXy çözümü olması gerektiğinden şüphelenmeye devam ediyorum, ancak tam olarak çözemiyorum. Gibi bir şey:

Başlangıçta, işleminiz belirli bir gruptaki tüm işlemlere bir 'kill -0' gönderir. Bu tür süreçler varsa, çıkar. Sonra gruba katılır. Başka hiçbir süreç bu grubu kullanmaz.

Bununla birlikte, bunun bir yarış koşulu vardır - birden çok süreç bunu tam olarak aynı anda yapabilir ve hepsi gruba katılarak eşzamanlı olarak koşabilir. Sızdırmaz hale getirmek için bir çeşit muteks eklediğinizde, artık işlem gruplarına ihtiyacınız yok.

İşleminiz yalnızca dakikada veya saatte bir cron tarafından başlatılıyorsa bu kabul edilebilir olabilir, ancak tam olarak istemediğiniz gün ters gitmesi beni biraz tedirgin ediyor.

Sanırım bu, birileri geliştiremediği sürece pek de iyi bir çözüm değil mi?


1

Geçen hafta bu problemle karşılaştım ve bazı iyi çözümler bulsam da çok basit ve temiz bir python paketi yapmaya karar verdim ve PyPI'ye yükledim. Herhangi bir dize kaynak adını kilitleyebilmesi açısından tendodan farklıdır. Yine __file__de aynı etkiyi elde etmek için kesinlikle kilitleyebilirsiniz .

Şununla yükle: pip install quicklock

Kullanmak son derece basittir:

[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> # Let's create a lock so that only one instance of a script will run
...
>>> singleton('hello world')
>>>
>>> # Let's try to do that again, this should fail
...
>>> singleton('hello world')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/nate/live/gallery/env/lib/python2.7/site-packages/quicklock/quicklock.py", line 47, in singleton
    raise RuntimeError('Resource <{}> is currently locked by <Process {}: "{}">'.format(resource, other_process.pid, other_process.name()))
RuntimeError: Resource <hello world> is currently locked by <Process 24801: "python">
>>>
>>> # But if we quit this process, we release the lock automatically
...
>>> ^D
[nate@Nates-MacBook-Pro-3 ~/live] python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from quicklock import singleton
>>> singleton('hello world')
>>>
>>> # No exception was thrown, we own 'hello world'!

Bir göz atın: https://pypi.python.org/pypi/quicklock


1
"Pip install quicklock" aracılığıyla kurdum, ancak "quicklock import singleton" ile kullanmaya çalıştığımda bir istisna alıyorum: "ImportError: 'singleton' adı içe aktarılamıyor. Bu bir Mac'te.
grayaii

Quicklock'un python 3 ile çalışmadığı ortaya çıktı. Benim için başarısız olmasının nedeni buydu.
grayaii

Evet, üzgünüm, geleceğe dönük hiç de değildi. Çalışması için bir katkıyı kabul edeceğim!
Nate Ferrero

1

Roberto Rosario'nun cevabına dayanarak şu işlevi buluyorum:

SOCKET = None
def run_single_instance(uniq_name):
    try:
        import socket
        global SOCKET
        SOCKET = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        ## Create an abstract socket, by prefixing it with null.
        # this relies on a feature only in linux, when current process quits, the
        # socket will be deleted.
        SOCKET.bind('\0' + uniq_name)
        return True
    except socket.error as e:
        return False

Küresel SOCKETdeğeri tanımlamamız gerekiyor çünkü yalnızca tüm süreç sona erdiğinde çöp toplanacak. İşlevde yerel bir değişken bildirirsek, işlev çıktıktan sonra kapsam dışına çıkacak, dolayısıyla soket silinecektir.

Tüm övgü Roberto Rosario'ya gitmeli, çünkü sadece kodunu açıklığa kavuşturup detaylandırıyorum. Ve bu kod, https://troydhanson.github.io/network/Unix_domain_sockets.html adresinden aşağıdaki alıntılanan metinde açıklandığı gibi yalnızca Linux'ta çalışacaktır :

Linux'un özel bir özelliği vardır: Bir UNIX etki alanı soketinin yol adı bir boş bayt \ 0 ile başlıyorsa, adı dosya sistemine eşlenmez. Böylece dosya sistemindeki diğer isimlerle çakışmaz. Ayrıca, bir sunucu soyut ad alanındaki UNIX etki alanı dinleme soketini kapattığında, dosyası silinir; normal UNIX etki alanı soketleriyle dosya, sunucu kapattıktan sonra da devam eder.


0

linux örneği

Bu yöntem, uygulamayı kapattıktan sonra otomatik olarak silinen geçici bir dosyanın oluşturulmasına dayanır. program başlatıldığında dosyanın varlığını doğrularız; dosya varsa (bekleyen bir yürütme varsa), program kapatılır; aksi takdirde dosyayı oluşturur ve programın yürütülmesine devam eder.

from tempfile import *
import time
import os
import sys


f = NamedTemporaryFile( prefix='lock01_', delete=True) if not [f  for f in     os.listdir('/tmp') if f.find('lock01_')!=-1] else sys.exit()

YOUR CODE COMES HERE

1
Stack Overflow'a hoş geldiniz! Bu cevap doğru olsa da, lütfen biraz açıklama ekleyin. Temel mantığı uygulamak, sadece kodu vermekten daha önemlidir, çünkü OP'nin ve diğer okuyucuların bu ve benzeri sorunları kendilerinin düzeltmesine yardımcı olur.
CodeMouse92

Bu konu güvenli mi? Görünüşe göre kontrol ve geçici dosya oluşturma atomik değil ...
coppit

0

Bir Linux sisteminde pgrep -aörnek sayısı da sorulabilir, komut dosyası süreç listesinde bulunur (-a seçeneği tam komut satırı dizesini gösterir). Örneğin

import os
import sys
import subprocess

procOut = subprocess.check_output( "/bin/pgrep -u $UID -a python", shell=True, 
                                   executable="/bin/bash", universal_newlines=True)

if procOut.count( os.path.basename(__file__)) > 1 :        
    sys.exit( ("found another instance of >{}<, quitting."
              ).format( os.path.basename(__file__)))

-u $UIDKısıtlamanın tüm kullanıcılar için geçerli olması gerekiyorsa kaldırın . Feragatname: a) betiğin (temel) adının benzersiz olduğu varsayılır, b) yarış koşulları olabilir.


-1
import sys,os

# start program
try:  # (1)
    os.unlink('lock')  # (2)
    fd=os.open("lock", os.O_CREAT|os.O_EXCL) # (3)  
except: 
    try: fd=os.open("lock", os.O_CREAT|os.O_EXCL) # (4) 
    except:  
        print "Another Program running !.."  # (5)
        sys.exit()  

# your program  ...
# ...

# exit program
try: os.close(fd)  # (6)
except: pass
try: os.unlink('lock')  
except: pass
sys.exit()  

2
Stack Overflow'a hoş geldiniz! Bu kod bloğu soruyu yanıtlasa da, bunu neden yaptığına dair küçük bir açıklama yapsanız en iyisi olur. Lütfen cevabınızı böyle bir açıklama içerecek şekilde düzenleyin .
Artjom B.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.