Soru Bir program çalışıyorsa programsal olarak belirleme


C, Linux / Ubuntu üzerinde bir işlem zaten iki kez başlamasını önlemek için çalışıyorsa nasıl programlayabilirim? Pidof'a benzer bir şey arıyorum.


25
2017-08-01 12:22


Menşei


(Program başlatılırken bilinen bir konumda geçici bir "kilit" dosyası oluşturabilir, daha sonra sadece dosyanın varlığını kontrol edebilirsiniz (ve eğer program beklenmedik bir şekilde sonlanırsa o zaman bir probleminiz olabilir) - - marnir
@marnir - programın kendi PID'sini dosyaya yazmanızın nedeni budur, eğer dosya varsa, bu PID'in hala aktif olup olmadığını ve eğer varsa, işlem adının sizinkiyle eşleşip eşleşmediğini kontrol edebilirsiniz. % 100 kusursuz değil ama yine de anormal sonlamalar olmamalı o genellikle. - George
"Kilit dosyası" programın PID'sini içeriyorsa, neredeyse tüm durumlarda anormal program sonlandırmayı algılayabilirsiniz (PID dosyasıyla eşleşen PID ile çalışan bir işlem var mı)? Bu mükemmel bir çözüm değildir (sınırlı sayıda PID, PID geri dönüşümü). - jmtd
@marnir - Kilit dosyasını gerçekten kilitlerseniz, kilit işlem çıkışında serbest bırakılır. Program sadece engellenmeyen özel bir kilit için çalışır ve başarısız olursa, başka biri çalışıyor. - unpythonic
Bunu Windows'da herkes nasıl yapar? - dm76


Cevaplar:


Yürüyebilirsin pid girişler /proc ve işleminizi ya cmdline dosya veya bir readlink üzerinde exe bağlantı (Aşağıdaki ilk yöntemi kullanır).

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char* endptr;
    char buf[512];

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        /* if endptr is not a null character, the directory is not
         * entirely numeric, so ignore it */
        long lpid = strtol(ent->d_name, &endptr, 10);
        if (*endptr != '\0') {
            continue;
        }

        /* try to open the cmdline file */
        snprintf(buf, sizeof(buf), "/proc/%ld/cmdline", lpid);
        FILE* fp = fopen(buf, "r");

        if (fp) {
            if (fgets(buf, sizeof(buf), fp) != NULL) {
                /* check the first token in the file, the program name */
                char* first = strtok(buf, " ");
                if (!strcmp(first, name)) {
                    fclose(fp);
                    closedir(dir);
                    return (pid_t)lpid;
                }
            }
            fclose(fp);
        }

    }

    closedir(dir);
    return -1;
}


int main(int argc, char* argv[]) 
{
    if (argc == 1) {
        fprintf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    int i;
    for(int i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}

26
2017-08-01 12:32



Bunu bir şov yapalım - bu kodu çalıştırmak için 500 ms civarında gösterilen her yineleme neden bu kadar uzun sürüyor? Bunu yapmak için daha iyi yollar var mı? - morty346
Çalıştığınız işlemlerin sayısına bağlıdır. - To1ne
Program adının önündeki dosya yolunu kaldırmaya ne dersiniz? Cmdline yerine comm kullanabilir misin? Ayrıca, öldürülen süreçleri nasıl görmezden geliyorsunuz? - gonzobrains


Kaçınılması gereken yollar var /proc kullanımı (ve bunu yapmak için iyi sebepler olabilir, ör. /proc hiç yüklenmemiş olabilir ve / veya aldatıcı bir şeye benzetilmiş olabilir ya da pid gizlenmiş /proc). Verilmiş, aşağıdaki yöntem iyi görünmüyor, keşke bunun için uygun bir API olsaydı!

Her neyse, Unix programlama SSS:

kullanım kill() Sinyal numarası için 0 ile. Bu çağrının dört olası sonucu var:

  • kill() 0 döndürür

    Bu, verilen PID ile bir işlemin var olduğunu ve       Sistem ona sinyal göndermenizi sağlar. Bu       sürece bağlı bir zombi olabilir sisteme bağımlı.

  • kill() -1 değerini döndürür errno == ESRCH

    Verilen PID veya güvenlik ile herhangi bir işlem yoktur.       Geliştirmeler, sistemin varlığını inkar etmesine neden oluyor. (Açık       Bazı sistemler, süreç bir zombi olabilir.)

  • kill() -1 değerini döndürür errno == EPERM

    Sistem belirtilen işlemi durdurmanıza izin vermez.       Bu, ya sürecin var olduğu anlamına gelir (yine, bir       zombi) veya zorlayıcı güvenlik geliştirmeleri var (ör.       işlem sinyal gönderemez kimse).

  • kill() diğer bir değeri ile -1 döndürür errno

    Başın belada!

En çok kullanılan teknik, başarı veya başarısızlık olduğunu varsaymaktır. EPERM işlemin var olduğunu ve başka herhangi bir hatanın bunun ima ettiğini ima eder. yapmaz.


13
2017-11-06 05:44



Sorunuzu yeniden okuduktan sonra ... tek yapmanız gereken işlemin iki kez çalıştırılmasını engelliyorsa, benzersiz bir isimle bir adlandırılmış çekirdek nesnesi (örneğin bir semafor veya paylaşılan bellek) oluşturabilir ve başlangıçta varlığını kontrol edebilirsiniz. . İşleminiz çökerse otomatik olarak gideceği için bir kilit dosyasından daha iyi olabilir. - RCL
Ancak proc kullanarak disk I / O erişiminiz olmayacaktır. - kayle
Tüm dosyalar disk erişimini gerektirmez. - RCL


Bu, John Ledbetter tarafından yayınlanan kodla aynı. Birincisi işlem durumları ve işlem adı verdiğinden beri / proc / pid / dizininde stat adı verilen dosyaya cmdline'dan daha çok başvurmak iyidir. Cmdline dosyası, sürecin başlatıldığı tam argümanlar verir. Yani bazı durumlarda bu başarısız olur. John'un verdiği fikir her şekilde iyidir. Burada John'un değiştirilmiş kodunu yayınladım. Dhcp'nin çalışıp çalışmadığını kontrol etmek için Linux'taki c'deki kodu arıyordum. Bu kodla bunu yapabilirim. Umarım benim gibi biri için yararlı olabilir.

#include <sys/types.h>
#include <dirent.h>
#include<unistd.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

pid_t proc_find(const char* name) 
{
    DIR* dir;
    struct dirent* ent;
    char buf[512];

    long  pid;
    char pname[100] = {0,};
    char state;
    FILE *fp=NULL; 

    if (!(dir = opendir("/proc"))) {
        perror("can't open /proc");
        return -1;
    }

    while((ent = readdir(dir)) != NULL) {
        long lpid = atol(ent->d_name);
        if(lpid < 0)
            continue;
        snprintf(buf, sizeof(buf), "/proc/%ld/stat", lpid);
        fp = fopen(buf, "r");

        if (fp) {
            if ( (fscanf(fp, "%ld (%[^)]) %c", &pid, pname, &state)) != 3 ){
                printf("fscanf failed \n");
                fclose(fp);
                closedir(dir);
                return -1; 
            }
            if (!strcmp(pname, name)) {
                fclose(fp);
                closedir(dir);
                return (pid_t)lpid;
            }
            fclose(fp);
        }
    }


closedir(dir);
return -1;
}


int main(int argc, char* argv[]) 
{
    int i;
    if (argc == 1) {
        printf("usage: %s name1 name2 ...\n", argv[0]);
        return 1;
    }

    for( i = 1; i < argc; ++i) {
        pid_t pid = proc_find(argv[i]);
        if (pid == -1) {
            printf("%s: not found\n", argv[i]);
        } else {
            printf("%s: %d\n", argv[i], pid);
        }
    }

    return 0;
}

11
2017-10-01 14:19



Neden yapmıyorsun readlink() üzerinde /proc/%ld/exe? - To1ne
Android 5.1'de, / proc / <PID> / stat içindeki işlem adı alanı oldukça küçük bir karakter sınırına sahiptir. Sadece bazı OS'lerin bu benzer problemi yaşayabileceğini düşünüyoruz. - Allen


pidof üzerinde yürümek /proc dosya sistemi. C'de, numaralandırma ile benzer bir şey yapabilirsiniz. /proc; açılış /proc/X/cmdline X'in her biri için X bir veya daha fazla ondalık sayıdır. Herhangi bir taşınabilirlik gereksiniminiz olup olmadığını bilmiyorum ancak uygunluğunuza güveniyorsanız /proc.

Bu sorun, programın başlatılması ve bir PID dosyasının tutulması ile UNIX benzeri sistemlerde daha sık çözülür. Görmek /etc/init.d/* Bu yaklaşımın klasik örnekleri için. Okunan kodun PID dosyasını güvenli bir şekilde (atomik olarak) yazmasını sağlamaya dikkat etmelisiniz. Hedef OS'niz daha yetenekli bir init varsa (örneğin systemd), bu işi bunun için kaynak haline getirebilirsiniz.


3
2017-08-01 12:27



Unix'in "yeterince iyi" olduğu ama neredeyse hiç şık olmadığı bir örnek. - Prof. Falken