Biten ancak bitmeyen bir program [kapalı]


35

Tamamlandığında tekrar başlayan bir program yazın.

Aynı anda çalışan programın birden fazla örneği olmamalıdır. En ufak bir an için bile değil.

Çevriminiz sırasında kullanıcı tarafından manuel olarak başlatılan herhangi bir örneği yok sayabilirsiniz. Ancak kodunuz yeniden başlatma döngünüzde yapılmamalıdır.

Program, bir süre sonra tekrar başlayacağının garantilendiği sürece başlayabilir.

Döngüyü durdurmanın tek yolu bu süreci öldürmektir.

Çözümünüz ortamın yeniden başlatılmasını içermemelidir (programın çalıştığı, işletim sistemi, makine, VM, kabuk vb. Dahil). Yalnızca programınız yeniden başlatılabilir.


11
Bu sadece execLinux'ta ne yapmıyor?
Şubat'ta

11
Şu anda yazmak için biraz tembelim, ancak gönderim (Windows için): "Programımı başlangıçta önyüklemesi için kayıt defterini düzenleyin. Çalıştır shutdown -r -t 0 -f".
Cruncher

3
Süreci öldürmek de olsa döngünüzü öldürmez.
microbian,

19
Yeni farkettim: bir virüs yazmak istiyorsam ve nasıl yapılacağını bilmiyorsam, 1) StackOverflow'a gidebilir, nasıl olduğunu sorun. Herkesten nefret edin ve muhtemelen soru kapanacaktır. Veya 2) Golf koduna gidin, başkalarına nasıl yaptıklarını sorun. Aralarından seçim yapabileceğiniz bir avuç yaratıcı cevap alın ve soru ağ genelinde "etkin" listede yer aldığı kadar popülerdir. Ha ha ha ha ha.
rumtscho

5
@ rumtscho Biliyorsunuz, bu iyi bir genel strateji. Tamam beyler, bir sonraki zorluğum için, masamda oturan prototip cihaz için en küçük firmware'i kimin yazabileceğini görelim. Baharatlamak için, bu pazartesi sabah 08: 00'a kadar yapılmalıdır. Gitmek!
Jason C,

Yanıtlar:


50

Bash senaryosu, 3 karakter (En kısa, belki de en zarif, şüphesiz tartışmalı olsa da)

$0&

Basitçe arka planda kendi kendine yeni bir örnek yerleştirir (yeni işlem), sonra çıkar. Yeni örnek büyük olasılıkla, önceki örnek tamamlanana kadar zamanlayıcı çalışma sırasında kalır.

Uyarı - bu zor kill PID sürekli olarak değiştiği . Komut dosyasını geçici olarak yeniden adlandırmak, muhtemelen döngüyü kırmanın en kolay yoludur.

Tek çekirdekli bir sistem olduğu varsayılmaktadır. Elbette bu, modern çıplak metal donanımda Linux ile gerçekçi değildir, ancak bir VM'de çalışırken kolayca yapılandırılabilir. Muhtemelen benzer bir numara kullanarak başarabiliriz.taskset , ancak bu 3-char çözümünün etkisini azaltacaktır.

Bu cevap, kuralları "biraz koşmak" için özel bir anlam uyguladığı için biraz eğmektedir. Yeni işlemin yapıldığı fork()ve eski işlemin hala hayatta olduğu anlar yaşanacaktır - yani birden fazla PID'nin gözlemlenmesi mümkün olabilir. Bununla birlikte, yeni işlem CPU döngülerini beklemek için Linux zamanlayıcı çalıştırma kuyruğuna yerleştirilirken mevcut işlem yürütülmeye devam eder. Bu noktada mevcut süreç tarafından yapılması gereken her şey bashkendisi içindir exit(). Bu, sınırlı bir zaman alır, ancak mevcut zaman dilimi / zamanlayıcı kuantumu yapılmadan önce bu şekilde uygulanacağından oldukça eminim. Kanıtları desteklemek bash, VM'mde 2 ms içinde başlayan ve kapanan olgudur :

$ time bash -c:

gerçek 0m0.002s
kullanıcı 0m0.000
Sys 0m0.000'ler
$ 

Yeni işlemin, önceki işlem yapılıncaya kadar yürütülmediğine dair ilave kanıtlar straceçıktıda görülebilir :

strace -f -tt -o forever.strace bash -c ./forever.sh 

Çıktıda orijinal sürecin PID 6929 olduğunu görüyoruz. Yeni bir 6930 PID döndüren fork()çağrıyı (aslında clone()) görebiliriz. Bu noktada 2 PID var, ancak şu anda yalnızca 6929 çalışıyor:

6929 12: 11: 01.031398 klonu (child_stack = 0, flags = CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | SIGCHLD, child_tidptr = 0x7f2f83ac49d0) = 6930
6929 12: 11: 01.031484 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0
6929 12: 11: 01.031531 rt_sigprocmask (SIG_BLOCK, [CHLD], [], 8) = 0
6929 12: 11: 01.031577 rt_sigprocmask (SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929 12: 11: 01.031608 rt_sigprocmask (SIG_SETMASK, [CHLD], NULL, 8) = 0
6929 12: 11: 01.031636 rt_sigprocmask (SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929 12: 11: 01.031665 rt_sigprocmask (SIG_SETMASK, [CHLD], NULL, 8) = 0
6929 12: 11: 01.031692 rt_sigprocmask (SIG_BLOCK, [CHLD], [CHLD], 8) = 0
6929 12: 11: 01.031726 rt_sigprocmask (SIG_SETMASK, [CHLD], NULL, 8) = 0
6929 12: 11: 01.031757 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0
6929 12: 11: 01.031803 rt_sigprocmask (SIG_BLOCK, NULL, [], 8) = 0
6929 12: 11: 01.031841 okuma (255, "", 4) = 0
6929 12: 11: 01.031907 çıkış grubu (0) =?
6930 12: 11: 01.032016 kapat (255) = 0
6930 12: 11: 01.032052 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0

straceBurada tam çıktı.

6930'un 6929 tamamen tamamlanıncaya kadar herhangi bir sistem çağrısı yapmadığını görebiliriz. Bunun, 6930'un, 6929 yapılıncaya kadar hiç çalışmadığını varsaymak mantıklıdır. Yardımcı perfprogram bunu kanıtlamanın nihai yolu olacaktır.


21
"yeniden başlatılıyor ... sonra da çıkıyor", yani aynı anda birden fazla örnek çalışıyor mu?
microbian,

4
“... tek çekirdekli” - evet, ben de öyle tahmin ediyorum. Çok çekirdekli bir ortamda, birçoğunu görmek mümkün olabilir.
blabla999

3
Bu kod-golf etiketli olsaydı, o zaman bu kesinlikle kazanacak! +1
John Odom

3
@DigitalTrauma Kendini kapatmanın ne kadar uzun sürdüğü konusunda çok büyük varsayımlarda bulunuyorsunuz. top size hiçbir şey söylemez - sadece birkaç saniyede bir (onlarca) saniyede bir güncellenir ancak saniyede birçok işlemi başlatırsınız.
David Richerby

2
@DavidRicherby - kesinlikle haklısın - topburada kullanmak için doğru araç değil. Ancak bunun time bash -c :Ubuntu VM'mde yalnızca 2ms aldığını görüyorum , bu yüzden bashzamanlama kuantumu yapılmadan önce kapanmasını tamamlamanın beklendiğini düşünmüyorum .
Dijital Travma,

26

1. Çözüm

PHP, 32 karakter

Başlığı gönderir ve sonra durur. 3 saniye sonra, sayfa yeniden yüklenir.

a.php dosyası

header("Refresh: 3; url=a.php");

Bu, başlıklar gönderilmeden önce sayfanın yürütülmesini durdurarak veya sadece tarayıcıyı öldürerek durdurulabilir.


2. Çözüm

PHP, 2 sayfa

İki dosyayı iki farklı program olarak düşünelim. İki dosya aynı klasördedir.

a.php dosyası

header("Location:b.php");

b.php dosyası

header("Location:a.php");

Sayfalardan birini başlıklar gönderilmeden sonlandırmak programı sonlandırır (tarayıcıyı da öldürmek).

İşte aynı programda

ASP.NET

a.aspx dosyası

Response.Redirect("b.aspx")

b.aspx dosyası

Response.Redirect("a.aspx")

1
Bu güzel bir çözüm. Umarım diğerleri bundan farklı cevaplarla gelir. Bu yüzden popülerlik yarışması olarak tuttum.
microbian

3 saniyelik yeniden yükleme yanıtınızın geçerli olup olmadığı, php uzmanlarına bırakıyorum. Bunun geçerli olabileceğini düşünüyorum, çünkü php'ınızı beklemeyen tarayıcıdır (uzman değilim).
microbian,

1
Teknik olarak PHP bir web sunucusunun modülü olarak çalıştırılsa ve web sunucunuz yeniden başlatılmamış olsa da, bir .php dosyasını bir komut dosyası olarak görürseniz ve komut dosyası birden çok kez çalıştırıldığında geçerli olur.
TwiNight

@TwiNight Geri bildiriminiz için teşekkür ederiz, minnettarım :)
Vereos

2
İkinci çözümünüz için, tarayıcı bir yönlendirme döngüsü algılayıp kendi başına durmaz mı? thedan1984.com/wp-content/uploads/2012/02/…
Ajedi32

19

sh

echo $PWD/$0 | at tomorrow

Bu herhangi bir Posix uyumlu sistem üzerinde çalışacaktır.

Öldürmek için dosyayı silin veya kullanın atrm.


17

darbe

exec "$0"

execyeni bir işlem oluşturmadan kabuğu değiştirir. Bu ikinci bir örnek olamayacağından emin olur.


1
İçine koymak daha iyi ~/.bash_profile!
yegle

@yegle: $0ne -bashzaman .bash_profilekaynaklanırsa, bu sadece sözdizimi hatasıyla sonuçlanır.
Dennis,

Oops, haklısın.
yegle

exec ${0##-}içinde ~/.bash_profile:-) eserlerin
yegle

14

Windows Görev Zamanlayıcısı (Yerel)

C ++. COM programlama kabusu. Tüm meydan okuma gereksinimlerini karşılar.

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <taskschd.h>
#include <comutil.h>

#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsuppw.lib")    

static void timeplus (int seconds, char timestr[30]);


int main () {

    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    CoInitializeSecurity(NULL, -1, NULL, NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);

    const char *name = "Restarter";

    char path[MAX_PATH + 1];
    GetModuleFileNameA(NULL, path, sizeof(path));
    path[sizeof(path) - 1] = 0; // workaround for xp

    ITaskService *taskman;
    CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER,
        IID_ITaskService, (void **)&taskman);

    taskman->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());

    ITaskFolder *root;
    taskman->GetFolder(_bstr_t("\\"), &root);

    // Delete the task.
    root->DeleteTask(_bstr_t(name), 0);

    // pause for 5 seconds to give user a chance to kill the cycle
    fprintf(stderr, "If you want to kill the program, close this window now.\n");
    Sleep(5000);
    fprintf(stderr, "Sorry, time's up, maybe next time.\n");

    // Create the task for 5 seconds from now.
    ITaskDefinition *task;
    taskman->NewTask(0, &task);

    IPrincipal *principal;
    task->get_Principal(&principal);
    principal->put_LogonType(TASK_LOGON_INTERACTIVE_TOKEN);

    ITaskSettings *settings;
    task->get_Settings(&settings);
    settings->put_StartWhenAvailable(VARIANT_TRUE);
    settings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
    settings->put_StopIfGoingOnBatteries(VARIANT_FALSE);

    ITriggerCollection *triggers;
    task->get_Triggers(&triggers);

    ITrigger *trigger;
    triggers->Create(TASK_TRIGGER_TIME, &trigger);

    char when[30];
    ITimeTrigger *trigger_time;
    trigger->QueryInterface(IID_ITimeTrigger, (void **)&trigger_time);
    trigger_time->put_Id(_bstr_t("TimeTrigger"));
    timeplus(10, when);
    trigger_time->put_StartBoundary(_bstr_t(when));
    timeplus(300, when);
    trigger_time->put_EndBoundary(_bstr_t(when));

    IActionCollection *actions;
    task->get_Actions(&actions);

    IAction *action;
    actions->Create(TASK_ACTION_EXEC, &action);

    IExecAction *action_exec;
    action->QueryInterface(IID_IExecAction, (void **)&action_exec);
    action_exec->put_Path(_bstr_t(path));

    IRegisteredTask *regtask;
    root->RegisterTaskDefinition(_bstr_t(name), task,
        TASK_CREATE_OR_UPDATE, _variant_t(), _variant_t(),
        TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(""),
        &regtask);

    regtask->Release();
    action_exec->Release();
    actions->Release();
    trigger_time->Release();
    trigger->Release();
    triggers->Release();
    settings->Release();
    principal->Release();
    task->Release();
    root->Release();
    taskman->Release();
    CoUninitialize();

}


// outputs current utc time + given number of seconds as 
// a string of the form YYYY-MM-DDTHH:MM:SSZ
static void timeplus (int seconds, char timestr[30]) {

    SYSTEMTIME when;
    FILETIME whenf;
    LARGE_INTEGER tempval;

    GetSystemTimeAsFileTime(&whenf);
    tempval.HighPart = whenf.dwHighDateTime;
    tempval.LowPart = whenf.dwLowDateTime;
    tempval.QuadPart += seconds * 10000000LL; // 100 nanosecond units
    whenf.dwHighDateTime = tempval.HighPart;
    whenf.dwLowDateTime = tempval.LowPart;
    FileTimeToSystemTime(&whenf, &when);

    sprintf(timestr, "%04hu-%02hu-%02huT%02hu:%02hu:%02huZ",
        when.wYear, when.wMonth, when.wDay,
        when.wHour, when.wMinute, when.wSecond);

}

MSVC ile derleyin (veya tüm bağımlılıklarınız varsa MinGW GCC).

Program, 5 saniye sonra kendi kendine başlaması için Windows görev zamanlayıcı ile bir defalık bir görevi başlatacak ve kaydedecektir (Denetim Masası -> Yönetimsel Araçlar -> Görev Zamanlayıcı'nın görüntülenmesi için, görev "Yeniden Başlat" olarak adlandırılır). Program, görevi oluşturmadan önce onu öldürme şansı vermek için 5 saniye duraklar.

Zorluk Gereksinimleri:

  • Tamamlandığında tekrar başlar. Evet. Görev programın çıkışından hemen önce planlanıyor.

  • Aynı anda çalışan programın birden fazla örneği yok. Evet. Program tamamen çıkıyor ve 5 saniye boyunca çalışmıyor. Zamanlayıcı tarafından başlatılır.

  • Çevriminiz sırasında kullanıcı tarafından manuel olarak başlatılan herhangi bir örneği yok sayabilirsiniz. Evet, sabit bir görev ismi kullanmanın yan etkisi olarak.

  • Tekrar başlamasının garanti edildiği sürece. Evet, Görev Zamanlayıcı'nın çalışması koşuluyla (standart bir Windows yapılandırmasında).

  • Döngüyü durdurmanın tek yolu bu süreci öldürmektir. Evet, işlem devam ederken 5 saniye boyunca işlem öldürülebilir. Program 5 saniyelik gecikmeden önceki görevi siler, bu sırada onu öldürmek zamanlayıcıda başıboş bir görev bırakmaz.

  • Çözümünüz çevrenin yeniden başlatılmasını içermemelidir . Evet.

Bu arada, herhangi biri Windows uygulamalarının neden bu kadar dengesiz olduklarını (.NET ve C # 'dan önce) hiç merak etmişlerse, bunun nedeni budur. Bir programcı en küçük bit tembel ise (yukarıdaki kod son derece tembelse), gereken hata işleme miktarı (buna dahil etmiş olsaydım), kaynak yönetimi ve ayrıntı ayrılığı çok hataya açık durumlar oluşturur.

Çok daha kolay ve daha kısa bir alternatif schtasks.exe'yi çağırmaktır. Bununla birlikte bir .BAT betiğinde de bir sürüm gönderdim .


13

BBC TEMEL - Kar Devriyesine bir haraç

Bbcbasic.co.uk şirketinde Emulator

Bu biraz farklı. "Run" adlı şarkının bir ayetini basar ve birlikte söyleyebilmeniz için akorların bir arpejini çalar. Yürütülecek komutun (ve dolayısıyla programın son satırının) elbette RUN olduğu gerçeğinden ilham almıştır.

Tüm değişkenler programın başında silinir, bu nedenle bir sonraki yinelemede ekran rengini geride bırakarak daha sonra ne yazılacağına karar verir.

    5 C=POINT(0,0) MOD 4
   10 COLOUR 129+C
   15 CLS
   20 RESTORE 110+C
   25 READ A$
   30 PRINT A$
   35 FORK = 1 TO 4
   40   RESTORE K+100
   45   READ P
   50   FORM= 1 TO 8
   55     SOUND 1,-15,P,7
   60     SOUND 1,-15,P-20,7
   65   NEXT
   70 NEXT
  101 DATA 100
  102 DATA 128
  103 DATA 136
  104 DATA 120
  110 DATA Light up light up - As if you have a choice - Even if you can not hear my voice - I'll be right beside you dear.
  111 DATA Louder louder - And we'll run for our lives - I can hardly speak - I understand - Why you can't raise your voice to say.
  112 DATA Slower Slower - We dont have time for that - All I want is to find an easier way - To get out of our little heads.
  113 DATA Have heart my dear - We're bound to be afraid - Even if its just for a few days - Makin' up for all of this mess.
  120 RUN

OUTPUT (4 farklı ekran görüntüsünün montajı)

görüntü tanımını buraya girin


"Paylaşılan hafıza" alternatifi olarak renk çözümü için +1.
Johannes H.

11

HTML / JavaScript:

<form /><script>document.forms[0].submit()</script>

Kod, üzerinde çalıştığı sayfanın imhasını tetikler, ardından tarayıcı sayfayı yeniden yüklediğinde kendi örneğinin yeniden oluşturulmasını tetikler.

AFAIK, tek çıkış yolu sayfanın içinde çalıştığı sekmeyi öldürmektir.

EDIT: popüler istek başına geçerli bir HTML5 kodu:

<!doctype html><meta charset=utf-8><title> </title><form></form>
<script>document.forms[0].submit()</script>

@JasonC Ben katılmıyorum. Makul sayfaların teknik özelliklere uyması gerektiğini düşünüyorum, ancak popülerlik yarışmasının makul olması bekleniyor, öyle değil mi? : D +1, bunu gerçekten beğendim.
sen

10

C

Bu program pek çok kötü amaçlı yazılım gibi davranır. Kapanmadan hemen önce, / tmp dizininde bir kabuk betiği oluşturur. Orijinal programın orijinal PID'yi kapatıp iptal etmesini sağlayan kabuk betiğini başlatması gerekir. Kısa bir süre sonra (2 saniye) kabuk betiği programda yeni bir işlem başlatır. Kısacası, program yeri '/ tmp / neverend /' olarak bağlanmıştır.

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

void rebirth(){
    char t[] = "/tmp/pawnXXXXXX";
    char* pawnfile = mktemp(t);
    if(pawnfile){
        int fd = open(pawnfile, O_RDWR|O_CREAT);
        const char msg[]="sleep 2\n/tmp/neverend\n";
        if(fd>0){
            int n = write(fd, msg, sizeof(msg));
            close(fd);
            pid_t pid = fork();
            if(pid==0){
                char* args[3] = {"bash", pawnfile, NULL};
                execvp(args[0], args);
            }
        }
    }
}

int main(int argc, char* argv[]){
    printf("Starting %s\n", argv[0]);
    atexit(rebirth);
    printf("Exiting %s\n", argv[0]);
}

Bir seferde çalışan yalnızca bir tek 'uçucu' süreci vardır. Her yeni işlem yeni bir PID alır. Bunu öldürmenin en kolay yolu çalıştırılabilir dosyayı silmektir. Daha kötü huylu hale getirmek isterseniz, programda istediğiniz zaman diskte birden fazla kopya olduğundan emin olmak için hem yürütülebilir dosyayı hem de komut dosyasını kopyalayabilirsiniz.


1
Daha yenilikçi cevaplar görmeyi bekliyorum. 'Ek programlar' ile ilgili sorulara bakın. Bana göre, ek bir program, programınızın takıldığı bir parçasıdır.
microbian

4
Forking, farklı şeyler yapsalar bile, aynı anda çalışan iki sürecin olacağı anlamına gelir.
Barry Fruitman

@BarryFruitman, gerçekte iki farklı çalıştırılabilir kullanarak, kaçınılması kolay. O zaman geçerli, ama daha az zarif.
Johannes H.

Sanırım system()kurallar bir çatal saymazsa + yürütürseniz /bin/shek bir program olarak kullanabilirsiniz.
Jason C

10

Perl

`perl -e"kill 9,$$"|perl $0`

Komut dosyası, kendisini öldürmek için bir sistem komutu yayınlar ve sonucu başka bir örneğe aktarır. Perl yorumlayıcısı, öldürme yapmak için çapraz platformdan dolayı kullanılır.

Senaryoyu silerek deliliği durdur.


7

Atari 8-bit Temel

1L.:R.

Tokenizler:

1 LIST : RUN

Dahili olarak, listeyi tekrar çalıştırmadan önce esas olarak programı silen iç yapıları temizliyor.

Bu temelde şunlardan farklıdır:

1L.:G.1

Hangi belirteçleri:

1 LIST : GOTO 1

Bu temel bir sonsuz döngüdür. Onları çalıştırdığınızda, hızdaki farkı görüyorsunuz (ilk önce daha yavaş).


Program yürütme sırasındaki "list" in neden iç yapıları ortadan kaldırdığı konusunda net değilim. Atari'nin bir klavye tamponu olduğunu düşünüyorum, böylece program listelenebilir, çalıştırılması için tuş vuruşlarını yapabilir ve imleci "yeniden yazmak" için "yeni" yapabilir.
supercat

@supercat - LIST, RUN yok.

Bu mantıkla kişi "LİSTE" yi atlayabilir. Diğer yandan, program klavyenin tamponunu doldurduysa, birkaç satır başı gelirse, ekranın sağındaki noktalara "YENİ" ve ardından "ÇALIŞTIR" ifadesi koydu, imleci tuttu ve çıktığında, kendini sildi. ve kendini otomatik olarak yeniden yazın.
supercat

@supercat - olmasaydı, LISTçalıştığını görmezsiniz. Seçtim LISTçünkü en kısa girdiye sahip L.. Bunu bir klavye tamponuna koyma fikrini seviyorum, kesinlikle yeterince kısa!

Commodore makineleri gibi Atari'nin siz ittiğinizde ekrandan metin okuduğunu doğru hatırlıyor muyum Return? Klavye arabelleği ne kadar büyük? VIC-20 ve C64'te, on bayttır. Klavye arabelleğini yüklemek için yeterince dürtme yapan bir program muhtemelen klavye arabelleğine sığmaz, ancak ekrana değişiklikleri izleyerek kendilerini değiştirecek programlar yazdım RUNve birkaç Returntuşa basacağım. Bu tür şeyler 64'te özellikle faydalıydı çünkü INAtari'nin bir programda çizgileri birleştirmek için sahip olduğu [IIRC] komutu yoktu .
supercat

5

Z / OS çalıştıran bir IBM Ana Bilgisayarında, bir veri kümesini (dosya) başka bir veri kümesine (dosya) kopyalayan bir yardımcı program çalıştırırsınız. Girdi, çalışması için gönderdiğiniz JCL'nin (İş Kontrol Dili) kaynağıdır. Çıkış, Dahili Okuyucu'dur (INTRDR). Ayrıca, sisteminizin birden fazla aynı iş adının çalıştırılmasına izin vermediğinden emin olmanız gerekir. Yalnızca bir başlatıcıya sahip bir iş sınıfı kullanmak iyi (bir JOB'in toplu olarak çalışabileceği yer).

Dahil olan PID yoktur (z / OS'de), bu nedenle zorluk setinde başarısız olur.

İşlemi boşaltarak ve / veya yıkayarak durdurursunuz. Bir şeyler ters gitti ise, tahliye ederek ve / veya yıkayarak, küfür ederek, tekmeleyerek, sıcak bir başlangıç ​​yaparak ve sonunda soğuk bir başlangıç ​​veya Büyük Kırmızı Düğmeye vurarak (ve programlayıcıyı vurarak).

Yol boyunca abartmış olabilirim, ama işte bunu denemeyin ...

SORT kullanarak örnek. JOB kartındaki detaylar siteye bağlıdır. Site politikası INTRDR kullanımını ya yasaklayabilir ya da önleyebilir. INTRDR'yi kullanmak için belirli bir sınıf gerekebilir. Site politikanızın kullanımını yasaklıyorsa, eşyalarınızı bir karton kutuya yürümek istemediğiniz sürece kullanmayınız .

INTRDR için iyi kullanımlar olmasına rağmen, bu amaç için kullanmayın . Kutunuzu alma şansınız bile yok.

//jobname JOB rest is to your site standards
//* 
//STEP0100 EXEC PGM=SORT 
//SYSOUT   DD SYSOUT=* 
//SORTOUT  DD SYSOUT=(,INTRDR) minimum required, site may require more 
//SYSIN    DD * 
  OPTION COPY 
//SORTIN   DD DISP=SHR,DSN=YOUR.LIBRARY.WITHJOB(JOBMEMBR) 

Diğer yardımcı programlar da mevcuttur. Hızlı bir program yapmak da kolay olurdu, sadece bir dosyayı okuyun, bir dosyayı yazın.

Bunun yanlış giden bir örnek istiyorsanız, şunu deneyin: http://ibmmainframes.com/viewtopic.php?p=282414#282414

Bir veri kümesini kopyalamanın geleneksel yolu, IBM yardımcı programı IEBGENER'i kullanmaktır;

Ancak bu günlerde, pek çok sitenin IEBGENER ICEGENER'e "diğer adı" olacak. SCEGENER, eğer yapabilirse, bir kopya yapmak için IBM'in DFSORT'unu (veya rakip SyncSort'unu) kullanacaktır, çünkü SORT ürünleri IO için IEBGENER'den çok daha iyi optimize edilmiştir.

Ben sadece SORT kullanarak orta adamı kesiyorum.

Bir IBM Ana Bilgisayar sitesinde çalışıyorsanız, kullanmanız gereken JOB kartının formatını biliyorsunuzdur. En az JOB kartı, yorum yapmadığım gibi. Yorum önemli olacaktır, çünkü örneğin muhasebe bilgileri sağlamanız gerekebilir. İş adı muhtemelen siteye özgü bir biçime sahip olacaktır.

Bazı siteler INTRDR kullanımını yasaklar veya engeller. Farkında olmak.

Bazı siteler, aynı ada sahip birden çok işin aynı anda çalışmasına izin verir. Farkında olmak.

Bir Sistemin Programcısı olmadığınız sürece, böyle bir sınıf oluşturamazsanız da, yalnızca bir başlatıcıya izin veren bir sınıf aramalısınız. Bununla, süreç oldukça güvenlidir - ancak sınıfın tanımlandığı gibi çalıştığından kesinlikle emin olun. Ölçek. Bu işte olmaz.

Eğer bir Sistemin Programcısıysanız, görevinizin dışında hiçbir şey yapmamanız gerektiğini bilirsiniz. 'Hayır dedi.

Aynı adda aynı anda izin verilen bir iş ve tek bir başlatıcı ile, bu işin başlamasıyla bir makarayı (yapması gereken başka bir şey) dolduruncaya kadar bir sonraki iş başlangıcında / bitişinde sürekli bir iş akışı olacak binlerce iş (veya iş sayısının tükenmesi). Uyarı mesajları için bir JES Konsolunu izleyin.

Temel olarak, bunu yapma. Bunu yaparsanız, Üretim makinesinde yapmayın.

Biraz fırçalama ile, başka bir IBM Mainframe işletim sisteminde nasıl yapılacağına ilişkin başka bir Yanıtı ele alacağım, z / VSE ... z / VSE, JCL kullanır. z / OS, JCL'yi kullanır. Onlar farklı :-)


Fikir iyi görünüyor, ama bir cevap değil. Bize JCL - JOB, EXEC ve DD - gösterin - o zaman bir cevap olacaktır.
ugoren

Çok uzun zamandır bir iş göndermedim, bu yüzden ne yapacağımdan emin değilim. Eksik parçalar sadece yerel özelleştirme ise, o zaman Tamam. Ancak, kötüye kullanımı önlemek için bir şeyler gizlerseniz, kararınızı verin - gerçek şeyi gönderin veya hiçbir şey göndermeyin. PS IEBGENERBasit kopyalamak için kullandık.
Şubat'ta ugoren

@ugoren IEBGENER'in görev için neden seçilmediğinin açıklamasını içeren bir güncelleme. JOB ifadesindeki yorum metnini kaldırmak, çalışması için gerekli JCL'yi verir, ancak yeterli JCL olması, işin çalışması veya programcının işten çıkarılmaması için yerel site standartlarına bağlıdır.
Bill Woodger

4

Python (72 bayt)

import os
os.system('kill -9 %s && python %s' % (os.getpid(), __file__))

Daha küçük olabilir sanırım. İlk önce, dosyanın adını kodlayarak (kullanmak yerine __file__). Fakat burada, bu kodu bir dosyaya koyabilir ve çalıştırabilirsiniz, adı ne olursa olsun :)


Muhtemelen değiştirebilir &&için &.
Hosch250

1
Ne zamandan beri izin veriliyor, user2509848?
Rhymoid

Peki, boşlukları kaldırarak başlayabilirsin…
Ry

6
Kod-golf etiketli olmadığı için, kodu şöyle yapacağım :-)
Maxime Lorant

4

Windows Görev Zamanlayıcısı (.BAT)

Windows toplu komut dosyası. Tüm meydan okuma gereksinimlerini karşılar.

Görebildiğim kadarıyla, şu ana kadar tüm gereklilikleri karşılayan ve standart olmayan bağımlılıkları olmayan tek Windows çözümüdür (diğer çözümüm benzer fakat derleme gerektirir).

@ECHO OFF
SETLOCAL

schtasks /Delete /TN RestarterCL /F

ECHO Close this window now to stop.
TIMEOUT /T 5

FOR /f "tokens=1-2 delims=: " %%a IN ("%TIME%") DO SET /A now=%%a*60+%%b
SET /A start=%now%+1
SET /A starth=100+(%start%/60)%%24
SET /A startm=100+%start%%%60
SET /A end=%now%+3
SET /A endh=100+(%end%/60)%%24
SET /A endm=100+%end%%%60

schtasks /Create /SC ONCE /TN RestarterCL /RI 1 /ST %starth:~1,2%:%startm:~1,2% /ET %endh:~1,2%:%endm:~1,2% /IT /Z /F /TR "%~dpnx0"

ENDLOCAL

Program benim C ++ / COM cevabına benzer şekilde davranıyor .

Program, bir kerelik görevi Windows görev zamanlayıcısına 60 saniye sonra başlayacak şekilde başlatacak ve kaydedecektir (Denetim Masası -> Yönetimsel Araçlar -> Görmek için Görev Zamanlayıcı, görev "Yeniden Başlatıcı" olarak adlandırılmıştır). Program, görevi oluşturmadan önce onu öldürme şansı vermek için 5 saniye duraklar.

Görev Zamanlayıcı arabirimi komut satırını kullanır schtasks.exe. Koddaki Aritmetik, zamanı geçerli ve HH: MM formatında tutarken zaman ofsetlerini hesaplamak içindir.

Zorluk Gereksinimleri:

  • Tamamlandığında tekrar başlar. Evet. Görev programın çıkışından hemen önce planlanıyor.

  • Aynı anda çalışan programın birden fazla örneği yok. Evet. Program tamamen çıkıyor ve ~ 60 saniye boyunca çalışmıyor. Zamanlayıcı tarafından başlatılır.

  • Çevriminiz sırasında kullanıcı tarafından manuel olarak başlatılan herhangi bir örneği yok sayabilirsiniz. Evet, sabit bir görev ismi kullanmanın yan etkisi olarak.

  • Tekrar başlamasının garanti edildiği sürece. Evet, Görev Zamanlayıcı'nın çalışıyor olması ve schtasks.exe'nin olması koşuluyla (her ikisi de varsayılan Windows yapılandırmalarında geçerlidir).

  • Döngüyü durdurmanın tek yolu bu süreci öldürmektir. Evet, işlem devam ederken 5 saniye boyunca işlem öldürülebilir. Program 5 saniyelik gecikmeden önceki görevi siler, bu sırada onu öldürmek zamanlayıcıda başıboş bir görev bırakmaz.

  • Çözümünüz çevrenin yeniden başlatılmasını içermemelidir . Evet.

Not: Sınırlı komut satırı arayüzü nedeniyle, yeniden başlatma zamanı dakika cinsinden belirtilmelidir ve AC adaptörü takılı olmadan dizüstü bilgisayarlarda görev yeniden başlatılmayacaktır (üzgünüm).


3

Unix kabuğu

Henüz yeniden başlatmak için alakasız bir programa dayanan pek çok çözüm görmedim. Ancak bu tam olarak at(1)programın yaptığı şeydi:

echo "/bin/sh $0"|at now + 1 minute

Çalışmakta olan programı yakalamak zor, çünkü sadece dakikada bir kez çalışıyor ve çok hızlı bir şekilde çıkıyor. Neyse ki, atq(1)yardımcı program size hala devam ettiğini gösterecek:

$ atq
493     Fri Feb 21 18:08:00 2014 a breadbox
$ sleep 60
$ atq
494     Fri Feb 21 18:09:00 2014 a breadbox

Ve atrm(1)bu döngüyü kırmana izin verecek:

$ atq
495     Fri Feb 21 18:10:00 2014 a breadbox
$ atrm 495
$ atq

Sen yerini alabilir 1 minuteile 1 hourveya 1 week. Veya 1461 daysher 4 yılda bir çalışan bir program olmasını sağlayın.


2

Güç kalkanı

Kendi kurallarımı kötüye kullanıyorum (ve muhtemelen çiğnedim).

[System.Threading.Thread]::Sleep(-1)

Kendini yeniden başlatmak için sonsuz zaman alır.
Ev sahibi işlemi öldürerek öldürülebilir.

Sadece bekle ve gör ;)


5
Yaratıcılık için + 1, aldatma için -1.
Johannes H.

1
Ha, ama hiç durmazsa "tekrar başlaması garanti edilir" mi?
Jason C

Bu yüzden muhtemelen kuralı çiğniyordum dedim. Bundan sonra her şeyin olabileceğini varsayabileceğiniz, sonsuzluğun felsefi güzelliği. Turing makinesi de bu şekilde çalışır.
microbian

1
-100, çünkü özellikle teknik bir konuda kendi yarışmanızı kazanmanızı desteklemiyorum, fakat +101, yeniden başlamasını beklemek şimdiye kadarki en iyi erteleme bahanesi.
Jason C

Biliyorsun, sonra while true; do sleep 1; doneyorganlaşıyor, değil mi?
sen

2

darbe

echo -e "$(crontab -l)\n$(($(date "+%M")+1)) $(date '+%H %e %m * /repeat.sh')" | crontab -

Bunu / dizininde repeat.sh dosyası olarak kaydedin ve çalıştırma izni verin. Dosyayı silerek öldürülebilir

Bu, 1 dakika sonra çalıştırmak için crontab'a bir giriş koyarak çalışır.


2

Görsel Taban 6 :)

Sub Main:Shell "cmd ping 1.1.1.1 -n 1 -w 500>nul&&"""&App.Path &"\"&App.EXEName& """":End Sub

Çalıştırmak, yeni bir proje oluşturmak, bu kodla bir modül eklemek, başlangıç ​​nesnesini "Sub Main" olarak ayarlamak, derlemek ve çalıştırılabilir dosyayı çalıştırmak.


Daha okunabilir sürüm:

Sub Main()
    Call Shell("cmd ping 1.1.1.1 -n 1 -w 3000 > nul && """ & App.Path & "\" & App.EXEName & """")
End Sub

VB6 gerçek bir erkeğin VB'sidir. Türünün sonuncusu!
Jason C,

1

HTML / JAVASCRIPT

HTML DOSYA a.html

<script>window.location = "a.html"</script>

1

darbe

Olması gerekenden daha uzun, ama yorgunum ve umrumda değil :)

while true; do sleep 1; done; bash $0;

Tamamlandığında kendini yeniden başlatması gerektiğini söylediniz, özellikle bunu tekrar tekrar ya da süresiz yapmak zorunda olduğunu söylemediniz. Ayrıca, asla aynı anda çalışan iki vakanın olmaması gerektiğini söyledin ... asla olmayacak. ;)

Bunu yapmanın çok sayıda yolu vardır. Benim kişisel favorim, uzak bir yere bir paket göndermek ve daha sonra (herhangi bir sayıda yöntemle) yanıtı işlemi tetiklemek gibi bir şey yapmak olacaktır.


Teknik olarak, sleepişlem bittiğinde işlem yeniden başlar
ace_HongKongIndependence 9

Program kendini yeniden başlatan bir programsa , o zaman bunu süresiz yapmak zorunda olduğu ima edilir - aksi halde kendisi olmayan bir şeyi yeniden başlatır .
Jason C,

@ Jason C: Çok felsefi olmadan, olabildiğince, kendini yeniden başlatır. Kendini gerçekten yeniden başlatmak için ne kadar karmaşık olduğunu tartışabiliriz , ancak bence yazarın kastettiği şeyin çok ötesinde. Yine de, kendisini gerçekten yeniden başlatmak istiyorsan, muhtemelen goto veya JMP kullanan bir şey ya da dilini yapabilecek her ne olursa olsun, başlangıcına geri dönmek için kendini yeniden başlatıyor. Aksi takdirde, sadece kendisi gibi kesin olan bir şeyi yerine getirir. Fakat o zaman birileri muhtemelen yeniden başlatılmayacağına dair bir sorun çıkaracak. Bu yüzden dalıyorum.
Ian Wizard

1

Android: Bir alarm 1 saniye sonra Etkinliği yeniden başlatacak

public class AutoRestart extends Activity
{

@Override
public void onCreate()
{
    finish();
}

@Override
public void onDestroy() {

    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
    restartServiceIntent.setPackage(getPackageName());

    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(
            AlarmManager.ELAPSED_REALTIME,
            SystemClock.elapsedRealtime() + 1000,
            restartServicePendingIntent);

    super.onDestroy();
}

}

1

C + MPI Ortamı

mpifork.c:

#include <stdio.h>

main(int argc, char * argv[])
{
    srand(time(NULL));
    int host = rand()%(argc-1)+1;
    FILE * logFile = fopen("mpifork.log", "a");
    if(logFile == NULL){
        fprintf(stderr, "Error: failed to open log file\n");
    } else {
        fprintf(logfile, "Jumping to %s\n", argv[host]);

        char * args[argc+5];
        args[0] = "mpirun";
        args[1] = "-H";
        args[2] = argv[host];
        args[3] = argv[0];
        for(host = 0; host < argc-1; host++) args[host+4] = argv[host+1];
        args[argc+3] = NULL;

        execvp("mpirun", args);
        fprintf(stderr, "exec died\n");
        perror("execvp");
    }
}

OpenMPI veya başka bir MPI uygulamasının kurulu olması gerekir. İle derleyin

mpicc -o mpifork mpifork.c

Şimdi düşünüyorum da, mpicc - gcc'yi kullanmak zorunda olmanızın bir nedeni yok. Sadece mpirun olmalı.

gcc -o mpifork mpifork.c

Çalıştırmak için, muhtemelen tam yol adını içermeli ve bir ana bilgisayar listesi eklemelisiniz. Örneğin, / etc / hosts dizininde tümü localhost'a işaret eden bazı girdiler ekledim ve şöyle yaptım:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

Yürütülebilir dosyayı, bunu çalıştırmak istediğiniz herhangi bir makinede aynı dizinde olması gerekir.


Temel olarak, bu komut satırında sağlanan ana bilgisayarların bir listesini alır, ana bilgisayarlardan birini seçer ve hedef ana bilgisayardaki yürütülebilir dosyayı aynı argümanlarla başlatır. Her şey mükemmel giderse, mpirun farklı makinelerde (veya yalnızca 'localhost' sağlarsanız aynı makinede) kendisini tekrar tekrar arayacak. Çalıştırılabilir kendisi (mpifork) sonlandırıyor - çağrıldıktan sonra execvp, ilk makinede çalıştırılmıyor.

Eğer kötülük yapmak isteseydiniz, bu fırlatmayı komut satırında verilen ana bilgisayarların tam listesini de dahil ederek her makinede yapabilirsiniz args. Bu, her bir makinenin kendi kopyasını tekrar tekrar topladı - bir küme çatalı.

Ancak, bu formda, bunun kuralları yerine getirdiğinden eminim.


1

JavaScript

Gerekli olmadığında “ağa gitmeden” :-) JavaScript'in olay döngüsü çizelgeleme, verilen gereksinimleri çok kolay karşılayan programlar yazmamızı sağlar:

(function program() {
    // do what needs to be done
    setTimeout(program, 100);
})();

Bu, programişlevi saniyede 10 kez hızla yeniden başlatır . JavaScript'in doğası gereği, aynı anda yalnızca tek bir görevin çalışacağı garanti edilir ve "sayfayı yeniden yükle" deki gibi "ortamı yeniden başlatmaz".


0

x86 Meclisi

Bunun tamamen yeni bir süreç oluşturmadığı için kriterlerinize uyduğundan emin değilsiniz ama yine de burada.

Program bir mesaj kutusu gösterecek, bir miktar bellek tahsis edecek, kendi kod bölümünü ayrılmış belleğe kopyalayacak ve daha sonra çevrimi başlatan o konuma atlayacaktır. Malloc başarısız olana kadar çalışması gerekir.

format PE GUI 4.0
entry a

include 'include/win32a.inc'

section '.text' code readable executable

    a:
        push    0
        push    _caption
        push    _message
        push    0
        call    [MessageBoxA]

        push    b-a
        call    [malloc]

        push    b-a
        push    a
        push    eax
        call    [memcpy]

        call    eax
    b:

section '.data' data readable writeable

    _caption db 'Code challenge',0
    _message db 'Hello World!',0

section '.idata' import data readable writeable

    library user,'USER32.DLL',\
        msvcrt,'msvcrt.dll'

    import user,\
        MessageBoxA,'MessageBoxA'

    import msvcrt,\
        malloc,'malloc',\
        memcpy,'memcpy'

Fasm ile derlendi.


4
Yeni kopyalanan kodu çağırmanız programınızın bir parçası olduğundan, teknik olarak programınız hiç bitmedi.
microbian

6
Düşük seviyeli bir bakış açısıyla, buradaki tüm programlar için aynı şey söylenebilir. :-)
Brian Knoblauch

@ BrianKnoblauch Ben katılmıyorum. Buradaki en ilginç cevaplar, sistem ortamını değiştiriyor gibi gözüküyor, böylece birincisinin öldürülmesinden bir süre sonra işlemin yeni bir kopyası başlatılıyor. Örneğin, gelecekte süreci yürütmek için bir chron işi yaratmanın, sürecin tamamen ölmesine ve ardından yeniden başlatılmasına izin vermenin iyi bir yolu olacağını düşünüyorum.
Kevin - Monica

2
@ BrianKnoblauch Gerçekten değil. Bir işlem bir işletim sistemi yapısıdır (bugünlerde - 1982’de 286’da korunan modun ortaya çıkmasından bu yana olduğu gibi - sanal adres alanları ve korumalı bellek yoluyla donanım tarafından da desteklenmektedir). Bittiğinde, tüm bu bilgiler kayboluyor. Yarışmada açıkça belirtilmediği halde, “yeniden başlatma” nın yeni bir süreç kimliğinin atandığı anlamına geldiği anlamına geliyor.
Jason C,

Şey, yoldayken hafızayı boşaltmayı başarabilseydin +1'i verirdim (lütfen @gözüm üzerinde kalmayacağımı düşündüğüm için bana bir kez uğraştırın ).
sen

0

Linux başlangıç ​​başlangıç

Sorunun en katı şekilde okunması durumunda bunun imkansız olduğunu düşünüyorum. Temelde, bir programın, başka çalışan hiçbir programın yardımı olmadan kendiliğinden başlamasını istemektedir.

Bazı atve chrontemelli cevaplar var, ancak en katı okuma ile atdve anacronsürekli çalışan tamamlayıcı programlar olduğu için diskalifiye edilebilirler.

İlgili bir yaklaşım, ancak biraz daha düşük bir düzeyde Linux kullanmak init. Kök olarak, bu .conf dosyasını şuraya ekleyin /etc/init/:

açıklama "sonsuza kadar"

runlevel'de başla [2345]
çalışma seviyesini durdur [! 2345]

respawn

10 uyku yürütmek

Ardından init.conf dosyalarını tekrar okuyun:

sudo telinit 5

Bu, sleep10 saniye boyunca yaşayacak bir işlemi başlatacak , sonra çıkacaktır. initsonra bir öncekinin sleepgittiğini tespit ettiğinde yeniden doğacak .

Tabii ki bu hala initek bir program olarak kullanıyor . initÇekirdeğin mantıklı bir uzantısı olduğunu ve her zaman herhangi bir Linux'ta kullanılabileceğini savunabilirsiniz .

Eğer bu kabul edilebilir değilse, o zaman yapılacak bir sonraki alt seviye işleminin bir kullanıcı alanı işlemini yeniden şekillendiren bir çekirdek modülü oluşturmak olacağını tahmin ediyorum (bunun ne kadar kolay olduğundan emin değilsiniz). Burada, çekirdeğin bir işlem olmadığı ve dolayısıyla bir program olmadığı (ek) olduğu söylenebilir. Öte yandan, çekirdek CPU'nun bakış açısından kendi başına bir programdır.


-1

TI-BASIC: 5 karakter

Bunu aramak prgmA

:prgmA

6 karakter sayabilirim. TI-BASIC program büyüklüğünü sayma konusunda özel bir şey var mı?
ace_HongKongIndependence

Bu :sadece TI-basic'de programlama yaparken satırın başlangıcıdır. Bu yazdığınız bir şey değil, sadece editörde var.
scrblnrd3

Bilgi için teşekkürler
ace_HongKongIndependence

Bu özyinelemeli çağrı değil mi? Arttırmayı Ave değerini temel durum olarak kullanmayı deneyin , sonunda çıkacağınızı göreceksiniz.
ζ--

Eh, tüm değişkenler ti-basic'de küreseldir, bu yüzden emin değilim. Olabilir
scrblnrd3
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.