Program, który się kończy, ale nigdy się nie kończy [zamknięty]

35

Napisz program, który uruchomi się ponownie po zakończeniu.

Jednocześnie nie powinno być uruchomionych więcej niż jedno wystąpienie programu. Nawet przez najdrobniejszy moment.

Możesz zignorować każde wystąpienie ręcznie uruchomione przez użytkownika podczas cyklu. Ale twój kod nie powinien tego robić w cyklu restartu.

Program można uruchomić po dowolnym czasie, o ile jest gwarantowane, że uruchomi się ponownie.

Jedynym sposobem na zatrzymanie cyklu jest zabicie procesu.

Twoje rozwiązanie nie powinno obejmować ponownego uruchamiania środowiska (w którym uruchomiony jest program, obejmuje system operacyjny, maszynę, maszynę wirtualną, powłokę itp.). Tylko twój program może się zrestartować.

drobnoustrój
źródło
11
Czy to nie tylko to, co execdziała w systemie Linux?
mniip
11
Jestem trochę leniwy, aby go teraz napisać, ale moje przesłanie brzmiałoby (w systemie Windows): „Edytuj rejestr, aby mój program uruchomił się przy uruchomieniu. Uruchom shutdown -r -t 0 -f”.
Cruncher
3
Zabicie tego procesu nie zabije jednak twojego cyklu.
drobnoustrój
19
Właśnie zdałem sobie sprawę: jeśli chcę napisać wirusa i nie wiem jak, mógłbym 1) przejść do StackOverflow, zapytać, jak to zrobić. Zdobądź nienawiść od wszystkich i prawdopodobnie pytanie zostanie zamknięte. Lub 2) Idź na golfa, zapytaj innych, jak by to zrobili. Uzyskaj garść kreatywnych odpowiedzi do wyboru, a pytanie jest tak popularne, że trafia na „gorącą” listę w całej sieci. Mua ha ha ha ha.
rumtscho
5
@rumtscho Wiesz, to dobra ogólna strategia. Ok, na moje następne wyzwanie, zobaczmy, kto może napisać najmniejsze oprogramowanie dla prototypowego urządzenia siedzącego na moim biurku, które spełnia wszystkie wymagania w połączonym dokumencie. Aby to urozmaicić, należy to zrobić do godziny 8 rano w poniedziałek rano. Udać się!
Jason C

Odpowiedzi:

50

Skrypt Bash, 3 znaki (najkrótszy, być może najbardziej elegancki, choć z pewnością kontrowersyjny)

$0&

Po prostu umieszcza nowe wystąpienie siebie w tle (nowy proces), a następnie kończy działanie. Nowa instancja prawdopodobnie pozostanie w kolejce uruchamiania programu planującego do czasu wykonania poprzedniej instancji.

Ostrzeżenie - jest to trudne kill, ponieważ PID ciągle się zmienia. Tymczasowa zmiana nazwy pliku skryptu jest prawdopodobnie najprostszym sposobem na przerwanie cyklu.

Zakłada się system jednordzeniowy. Oczywiście nie jest to realistyczne w przypadku Linuksa na nowoczesnym sprzęcie typu bare-metal, ale można go łatwo skonfigurować podczas pracy na maszynie wirtualnej. Prawdopodobnie moglibyśmy osiągnąć podobną sztuczkę taskset, ale zmniejszyłoby to wpływ rozwiązania 3-char.

Ta odpowiedź nieco wygina reguły, ponieważ stosuje określone znaczenie „biegania”. Będą chwile, kiedy nowy proces zostanie fork()zmodyfikowany, a stary proces będzie nadal żywy - tzn. Możliwe będzie zaobserwowanie więcej niż jednego PID. Jednak nowy proces zostanie umieszczony w kolejce uruchomieniowej programu planującego Linux w celu oczekiwania na cykle procesora, podczas gdy istniejący proces będzie kontynuowany. W tym momencie wszystko, co musi być zrobione przez istniejący proces, jest dla bashsiebie exit(). Zajmuje to skończoną ilość czasu, choć jestem całkiem pewien, że zostanie to zrobione na długo przed wykonaniem bieżącej kwanty czasu / harmonogramu. Potwierdzającym dowodem jest fakt, że bashuruchamia się i wyłącza w 2ms na mojej maszynie wirtualnej:

$ time bash -c:

prawdziwe 0m0,002s
użytkownik 0m0.000s
sys 0m0.000s
$ 

Dalsze dowody potwierdzające, że nowy proces faktycznie nie działa, dopóki poprzedni proces nie zostanie wykonany, można znaleźć w stracedanych wyjściowych:

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

Na wyjściu widzimy, że pierwotny proces ma PID 6929. Widzimy fork()wywołanie (faktycznie clone()), które zwraca nowy PID 6930. W tym momencie są 2 PID, ale obecnie tylko 6929 działa:

6929 12: 11: 01.031398 klon (child_stack = 0, flagi = 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 odczytane (255, „”, 4) = 0
6929 12: 11: 01.031907 grupa_wyjścia (0) =?
6930 12: 11: 01.032016 zamknij (255) = 0
6930 12: 11: 01.032052 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0

Pełna stracemoc tutaj.

Widzimy, że 6930 nie generuje żadnych wywołań systemowych, dopóki 6929 nie zostanie całkowicie wykonane. Można założyć, że oznacza to, że 6930 w ogóle nie działa, dopóki nie zostanie wykonane 6929. perfNarzędzie byłby najlepszy sposób to udowodnić.

Cyfrowa trauma
źródło
21
„uruchamia się ponownie, a następnie kończy pracę”, więc jednocześnie działa więcej niż jedna instancja?
drobnoustrój
4
„... na jednym rdzeniu” - tak, też tak sądzę. Na wielu rdzeniach możesz prawdopodobnie zobaczyć wiele.
blabla999
3
Jeśli oznaczono to kodem golfowym, to na pewno wygra! +1
John Odom
3
@DigitalTrauma Robisz ogromne założenia, ile czasu zajmuje bash, aby się zamknąć. top mówi nic - aktualizuje się tylko raz na kilka (kilkadziesiąt) sekund, ale odradzasz wiele procesów na sekundę.
David Richerby
2
@DavidRicherby - masz absolutną rację - topnie jest odpowiednim narzędziem do użycia tutaj. Widzę jednak, że time bash -c :zajmuje to tylko 2ms na mojej maszynie Wirtualnej Ubuntu, więc nie sądzę, że nierozsądne jest oczekiwanie bashzakończenia procesu zamykania przed ukończeniem kwantowania.
Cyfrowa trauma
26

Rozwiązanie 1

PHP, 32 znaki

Wysyła nagłówek, a następnie zatrzymuje się. Po 3 sekundach strona zostanie ponownie załadowana.

plik a.php

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

Można to zatrzymać, przerywając wykonywanie strony przed wysłaniem nagłówków lub po prostu zabijając przeglądarkę.


Rozwiązanie 2

PHP, 2 strony

Rozważmy dwa pliki dwa różne programy. Dwa pliki znajdują się w tym samym folderze.

plik a.php

header("Location:b.php");

plik b.php

header("Location:a.php");

Zakończenie jednej ze stron przed wysłaniem nagłówków powoduje zakończenie programu (zabija również przeglądarkę).

Oto ten sam program w

ASP.NET

plik a.aspx

Response.Redirect("b.aspx")

plik b.aspx

Response.Redirect("a.aspx")
Vereos
źródło
1
To miłe rozwiązanie. Mam nadzieję, że inni otrzymają odpowiedzi inne niż to. Dlatego utrzymałem to jako konkurs popularności.
drobnoustrój
Niezależnie od tego, czy Twoja 3-sekundowa odpowiedź przeładowania jest poprawna, czy nie, pozostawiam ją ekspertom php. Myślę, że może to być poprawne, ponieważ to przeglądarka nie czeka na twojego php (nie jestem ekspertem).
drobnoustrój
1
Chociaż technicznie PHP jest uruchamiane jako moduł serwera WWW, a serwer nie uruchomił się ponownie, myślę, że jest poprawny, jeśli uważasz plik .php za skrypt, a skrypt jest uruchamiany wiele razy.
TwiNight
@TwiNight Dzięki za opinie, doceniam to :)
Vereos
2
Czy w przypadku drugiego rozwiązania przeglądarka nie wykryje pętli przekierowań i nie zatrzyma się sama? thedan1984.com/wp-content/uploads/2012/02/…
Ajedi32
19

sh

echo $PWD/$0 | at tomorrow

Działa to na każdym systemie zgodnym z Posix.

Aby go zabić, usuń plik lub użyj atrm.

ecatmur
źródło
17

grzmotnąć

exec "$0"

execzastępuje powłokę bez tworzenia nowego procesu. Dzięki temu nie będzie drugiej instancji.

Dennis
źródło
1
Lepiej to włóż ~/.bash_profile!
yegle
@yegle: $0jest -bashkiedy .bash_profilejest pozyskiwany, więc spowodowałoby to tylko błąd składniowy.
Dennis
Ups, masz rację.
yegle
exec ${0##-}w ~/.bash_profilepracach :-)
yegle
14

Harmonogram zadań systemu Windows (macierzysty)

C ++. Koszmar programowania COM. Spełnia wszystkie wymagania dotyczące wyzwań.

#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);

}

Kompiluj z MSVC (lub MinGW GCC, jeśli masz wszystkie zależności).

Program uruchomi i zarejestruje jednorazowe zadanie w harmonogramie zadań systemu Windows, aby uruchomić się 5 sekund później (Panel sterowania -> Narzędzia administracyjne -> Harmonogram zadań do wyświetlenia, zadanie nosi nazwę „Uruchom ponownie”). Program zatrzyma się na 5 sekund, aby dać ci szansę zabicia go, zanim utworzy zadanie.

Wymagania dotyczące wyzwań:

  • Uruchamia się ponownie po zakończeniu. Tak. Zadanie jest zaplanowane tuż przed wyjściem z programu.

  • Nie więcej niż jedna instancja programu działającego w tym samym czasie. Tak. Program kończy się całkowicie i nie działa przez 5 sekund. Jest uruchamiany przez program planujący.

  • Możesz zignorować każde wystąpienie ręcznie uruchomione przez użytkownika podczas cyklu. Tak, jako efekt uboczny używania stałej nazwy zadania.

  • Tak długo, jak jest gwarantowane, że zacznie się od nowa. Tak, pod warunkiem, że Harmonogram zadań jest uruchomiony (jest w standardowej konfiguracji systemu Windows).

  • Jedynym sposobem na zatrzymanie cyklu jest zabicie procesu. Tak, proces może zostać zabity podczas trwającego 5 sekund okna. Program usuwa zadanie przed 5-sekundowym opóźnieniem, zabicie go w tym momencie nie pozostawi zbłąkanego zadania w harmonogramie.

  • Twoje rozwiązanie nie powinno obejmować ponownego uruchamiania środowiska Tak.

Nawiasem mówiąc, jeśli ktoś kiedykolwiek zastanawiał się, dlaczego aplikacje Windows były tak niestabilne (przed pojawieniem się .NET i C #), jest to jeden z powodów. Wymagana obsługa błędów (gdybym to załączyła), zarządzanie zasobami i gadatliwość ustawiają sytuacje podatne na błędy, jeśli programista jest nawet trochę leniwy (powyższy kod jest bardzo leniwy).

O wiele łatwiejszą i krótszą alternatywą jest wywołanie schtasks.exe. Przesłałem również tę wersję w skrypcie .BAT .

Jason C.
źródło
13

BBC BASIC - hołd dla Snow Patrol

Emulator na bbcbasic.co.uk

Ten jest trochę inny. Drukuje wiersz utworu „Run” i odtwarza arpeggio akordów, abyś mógł śpiewać. Został zainspirowany faktem, że polecenie wykonania (a zatem i ostatniego wiersza programu) to oczywiście RUN.

Wszystkie zmienne są usuwane na początku programu, więc zabiera kolor ekranu pozostawiony przez poprzednią iterację, aby zdecydować, który wiersz należy wydrukować w następnej kolejności.

    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

WYDAJNOŚĆ (montaż 4 różnych zrzutów ekranu)

wprowadź opis zdjęcia tutaj

Level River St
źródło
+1 dla rozwiązania kolorowego jako alternatywy „pamięci współdzielonej”.
Johannes H.
11

HTML / JavaScript:

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

Kod powoduje zniszczenie strony, na której działa, a następnie odtworzenie innej instancji samego siebie, gdy przeglądarka ponownie ładuje stronę.

AFAIK, jedynym wyjściem jest zabicie zakładki, na której działa strona.

EDYCJA: zgodnie z popularnym żądaniem prawidłowy kod HTML5:

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

źródło
@JasonC Nie zgadzam się. Myślę, że rozsądne strony powinny być zgodne ze specyfikacjami, ale konkursy popularności powinny być rozsądne, prawda? : D, więc +1, naprawdę podoba mi się ten.
jo
10

do

Ten program działa jak dużo złośliwego oprogramowania. Tuż przed zamknięciem tworzy skrypt powłoki w katalogu / tmp. Widoczne jest uruchomienie skryptu powłoki, który pozwala oryginalnemu programowi zamknąć i anulować oryginalny PID. Po krótkim czasie (2 sekundy) skrypt powłoki rozpoczyna nowy proces z programem. Dla zwięzłości lokalizacja programu jest ustalona jako „/ tmp / neverend /”.

#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]);
}

W danym momencie działa tylko jeden „niekończący się” proces. Każdy nowy proces otrzymuje nowy PID. Najłatwiejszym sposobem na zabicie tego jest usunięcie pliku wykonywalnego. Jeśli chcesz uczynić go bardziej złośliwym, możesz skopiować zarówno plik wykonywalny, jak i skrypt, aby upewnić się, że w programie jest wiele kopii na dysku w dowolnym momencie.

Kevin
źródło
1
Spodziewam się bardziej innowacyjnych odpowiedzi. Zobacz komentarze do pytania na temat „programów uzupełniających”. Dla mnie program uzupełniający jest tylko częścią twojego programu, który się kręci.
drobnoustrój
4
Rozwidlenie oznacza, że ​​będziesz mieć jednocześnie dwie instancje procesu, nawet jeśli robią one różne rzeczy.
Barry Fruitman
@BarryFruitman jest jednak łatwy do uniknięcia dzięki zastosowaniu dwóch różnych plików wykonywalnych. Jest to ważne, ale o wiele mniej eleganckie.
Johannes H.
Przypuszczam, że możesz użyć, system()jeśli reguły nie liczą fork + exec /bin/shjako programu dodatkowego.
Jason C
10

Perl

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

Skrypt wydaje polecenie systemowe, aby się zabić, i przesłać wynik do innej instancji samego siebie. Interpreter Perla jest używany do zabijania, z powodów wieloplatformowych.

Zatrzymaj szaleństwo, usuwając skrypt.

primo
źródło
7

Atari 8-bit Basic

1L.:R.

Tokenizuje do:

1 LIST : RUN

Wewnętrznie usuwa wewnętrzne struktury, zasadniczo usuwając program, zanim ponownie uruchomi go z listingu.

To zasadniczo różni się od:

1L.:G.1

Który symbolizuje:

1 LIST : GOTO 1

Jest to podstawowa nieskończona pętla. Kiedy je uruchomisz, zobaczysz różnicę prędkości (pierwsza jest wolniejsza).


źródło
Nie jestem do końca jasne, dlaczego „lista” podczas wykonywania programu wyczyściła struktury wewnętrzne. Myślę, że Atari ma bufor klawiatury, więc można było wypisać program, wcisnąć klawisze, aby go uruchomić, i zrobić „nowy”, gdy kursor jest ustawiony, aby go „wpisać”.
supercat
@ supercat - LISTA nie, RUN robi.
Zgodnie z tą logiką można pominąć „LISTĘ”. Z drugiej strony, jeśli program wypchnie bufor klawiatury, kilkoma znakami powrotu karetki, wstawi „NEW”, następnie program i „RUN” w odpowiednich miejscach na ekranie, umieści kursor na kursie i wyjdzie, to naprawdę skasuje się i ponownie wpisz się automatycznie.
supercat
@ superupcat - bez niego LISTnie zobaczysz, że działa. Wybrałem, LISTponieważ ma najkrótsze wejście L.. Podoba mi się pomysł umieszczenia tego w buforze klawiatury, z pewnością jest wystarczająco krótki!
Czy dobrze pamiętam, że Atari, podobnie jak maszyny Commodore, czyta tekst po naciśnięciu przycisku Return? Jak duży jest bufor klawiatury? W VIC-20 i C64 ma dziesięć bajtów. Program, który robi wystarczająco dużo nacisków, aby załadować bufor klawiatury, prawdopodobnie nie zmieściłby się w buforze klawiatury, ale napisałem programy, które same się modyfikowałyby, drukując zmiany na ekranie, a następnie RUNwprowadziły kilka Returnnaciśnięć klawiszy. Takie rzeczy były szczególnie przydatne na 64, ponieważ nie miał polecenia [IIRC], które INAtari ma do łączenia linii w program.
supercat
5

Na komputerze mainframe IBM z systemem operacyjnym z / OS uruchamiane jest narzędzie, które kopiuje zestaw danych (plik) do innego zestawu danych (plik). Dane wejściowe są źródłem przesłanego języka JCL (Job Control Language), który spowodował jego uruchomienie. Wyjściem jest czytnik wewnętrzny (INTRDR). Musisz także upewnić się, że Twój system nie pozwala na uruchamianie wielu identycznych nazw zadań. Dobrze jest użyć klasy zadania, która ma tylko jednego inicjatora (miejsce, w którym zadanie może działać wsadowo).

Brak zaangażowanych identyfikatorów PID (w systemie z / OS), więc nie powiedzie się zestaw wyzwań.

Zatrzymujesz proces, opróżniając i / lub spłukując. Jeśli coś poszło nie tak, poprzez drenaż i / lub spłukiwanie, przeklinanie, kopanie, próbę ciepłego startu i wreszcie przez zimny start lub uderzenie w Big Red Button (i strzelanie do programisty).

Mogłem przesadzać po drodze, ale nie próbuj tego w pracy ...

Przykład użycia SORT. Szczegóły dotyczące karty JOB są bardzo zależne od strony. Zasady witryny mogą zabraniać lub uniemożliwiać korzystanie z INTRDR. Do korzystania z INTRDR może być wymagana konkretna klasa. Jeśli zasady witryny zabraniają korzystania z niego , nie używaj go, chyba że chcesz zabrać swoje rzeczy na spacer w tekturowym pudełku.

Chociaż INTRDR ma dobre zastosowania, nie należy go używać do tego celu . Nie będziesz nawet mieć szansy na zdobycie swojego pudełka.

//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) 

Inne narzędzia są dostępne. Szybki program byłby również łatwy do zrobienia, wystarczy przeczytać plik, napisać plik.

Jeśli chcesz, aby przykład tego nie powiódł się, spróbuj: http://ibmmainframes.com/viewtopic.php?p=282414#282414

Tradycyjnym sposobem kopiowania zestawu danych jest użycie narzędzia IBM IEBGENER, jak ugoren wspomina w swoim komentarzu.

Jednak w dzisiejszych czasach wiele witryn będzie miało „alias” IEBGENER do ICEGENER. Jeśli to możliwe, ICEGENER użyje DFSORT IBM (lub jego konkurencyjnego SyncSort) do wykonania kopii, ponieważ produkty SORT są znacznie bardziej zoptymalizowane pod kątem IO niż IEBGENER.

Właśnie wycinam środkowego człowieka za pomocą SORT.

Jeśli pracujesz w serwisie IBM Mainframe, znasz format karty JOB, której powinieneś używać. Minimalna karta JOB jest, jak pokazałem, bez komentarza. Komentarz będzie ważny, ponieważ na przykład możesz podać informacje księgowe. Nazwa zadania prawdopodobnie będzie miała format specyficzny dla witryny.

Niektóre witryny blokują lub uniemożliwiają korzystanie z INTRDR. Być świadomym.

Niektóre witryny umożliwiają jednoczesne uruchamianie wielu zadań o tej samej nazwie. Być świadomym.

Chociaż chyba, że ​​nie jesteś programistą systemu, nie możesz skonfigurować takiej klasy, powinieneś poszukać klasy, która zezwala tylko na jednego inicjatora. Dzięki temu proces jest dość bezpieczny - ale bądź absolutnie pewien, że klasa działa zgodnie z opisem. Test. Nie z tą pracą.

Jeśli jesteś programistą systemu, wiesz, że nie możesz nic robić poza twoim zakresem kompetencji. powiedział nuff.

Przy jednym zadaniu o tej samej nazwie dozwolonym w tym samym czasie i pojedynczym inicjatorze będzie to ciągły strumień rozpoczęcia / zakończenia zadania następny początek / koniec zadania - dopóki nie wypełni się szpuli (kolejna zła rzecz do zrobienia) danymi wyjściowymi z tysiące zadań (lub zabrakło numerów zadań). Obserwuj konsolę JES pod kątem komunikatów ostrzegawczych.

Zasadniczo nie rób tego. Jeśli to zrobisz, nie rób tego na maszynie produkcyjnej.

Przy odrobinie odświeżenia rozważę kolejną odpowiedź na pytanie, jak to zrobić w innym systemie operacyjnym IBM Mainframe, z / VSE ... z / VSE używa JCL. z / OS używa JCL. Oni są różni :-)

Bill Woodger
źródło
Pomysł wygląda dobrze, ale nie jest odpowiedzią. Pokaż nam JCL - JOB, EXEC i DD - to będzie odpowiedź.
ugoren
Okropnie długo nie pracowałem, więc nie jestem pewien, co z tym zrobić. Jeśli brakujące części to tylko lokalne dostosowanie, to OK. Ale jeśli ukrywasz rzeczy, aby zapobiec nadużyciom, to zdecyduj - opublikuj prawdziwą wiadomość lub nic nie publikuj. PS W IEBGENERtamtych czasach zwykliśmy kopiować.
ugoren
@ugoren Dalsza aktualizacja, w tym wyjaśnienie, dlaczego dla zadania nie wybrano IEBGENER. Usunięcie tekstu komentarza z instrukcji JOB daje niezbędne JCL do uruchomienia, ale jego wystarczająca JCL zależy od lokalnych standardów witryny, zarówno dla zadania do działania, jak i dla programisty, aby uniknąć zwolnienia.
Bill Woodger
4

Python (72 bajty)

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

Może być mniejszy. Po pierwsze, wpisując na stałe nazwę pliku (zamiast używać __file__). Ale tutaj możesz umieścić ten kod w pliku i uruchomić go, niezależnie od jego nazwy :)

Maxime Lorant
źródło
Prawdopodobnie możesz zmienić &&na &.
Hosch250
1
Od kiedy to jest dozwolone, user2509848?
Rhymoid
Cóż, możesz zacząć od usunięcia białych znaków…
Ry-
6
Ponieważ nie jest oznaczony kodem golfowym , zachowam kod w ten sposób :-)
Maxime Lorant,
4

Harmonogram zadań systemu Windows (.BAT)

Skrypt wsadowy Windows. Spełnia wszystkie wymagania dotyczące wyzwań.

O ile widzę, jest to jedyne jak dotąd rozwiązanie Windows, które spełnia wszystkie wymagania i nie ma niestandardowych zależności (moje inne rozwiązanie jest podobne, ale wymaga kompilacji).

@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 zachowuje się podobnie do mojej odpowiedzi C ++ / COM .

Program uruchomi i zarejestruje jednorazowe zadanie w harmonogramie zadań systemu Windows, aby uruchomić się do 60 sekund później (Panel sterowania -> Narzędzia administracyjne -> Harmonogram zadań do wyświetlenia, zadanie nosi nazwę „Uruchom ponownie”). Program zatrzyma się na 5 sekund, aby dać ci szansę zabicia go, zanim utworzy zadanie.

Wykorzystuje interfejs harmonogramu zadań wiersza poleceń schtasks.exe . Arytmetyka w skrypcie polega na obliczaniu przesunięć czasowych przy zachowaniu aktualności czasu w formacie GG: MM.

Wymagania dotyczące wyzwań:

  • Uruchamia się ponownie po zakończeniu. Tak. Zadanie jest zaplanowane tuż przed wyjściem z programu.

  • Nie więcej niż jedna instancja programu działającego w tym samym czasie. Tak. Program kończy się całkowicie i nie działa przez ~ 60 sekund. Jest uruchamiany przez program planujący.

  • Możesz zignorować każde wystąpienie ręcznie uruchomione przez użytkownika podczas cyklu. Tak, jako efekt uboczny używania stałej nazwy zadania.

  • Tak długo, jak jest gwarantowane, że zacznie się od nowa. Tak, pod warunkiem, że Harmonogram zadań jest uruchomiony, a program schtasks.exe jest obecny (oba są prawdziwe w domyślnych konfiguracjach systemu Windows).

  • Jedynym sposobem na zatrzymanie cyklu jest zabicie procesu. Tak, proces może zostać zabity podczas trwającego 5 sekund okna. Program usuwa zadanie przed 5-sekundowym opóźnieniem, zabicie go w tym momencie nie pozostawi zbłąkanego zadania w harmonogramie.

  • Twoje rozwiązanie nie powinno obejmować ponownego uruchamiania środowiska Tak.

Uwaga: Z powodu ograniczonego interfejsu wiersza poleceń czas ponownego uruchomienia musi być określony w minutach, a zadanie nie uruchomi się ponownie na laptopach bez podłączonego zasilacza sieciowego (przepraszam).

Jason C.
źródło
3

Powłoka Unix

Nie widziałem jeszcze wielu rozwiązań, które polegają na niezwiązanym programie do jego ponownego uruchomienia. Ale właśnie do tego at(1)służy narzędzie:

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

Naprawdę trudno jest złapać uruchomiony program, ponieważ działa on tylko raz na minutę i kończy się tak szybko. Na szczęście atq(1)narzędzie pokaże, że nadal działa:

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

I atrm(1)pozwoli ci przerwać cykl:

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

Można wymienić 1 minutez 1 hourlub 1 week. Możesz też dać 1461 daysprogram, który będzie uruchamiany raz na 4 lata.

chlebak
źródło
2

PowerShell

Nadużywam (i prawdopodobnie łamię) własną zasadę.

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

Ponowne uruchomienie się zajmuje nieskończoną ilość czasu.
Można go zabić, zabijając proces hosta.

Po prostu poczekaj i zobacz;)

drobnoustrój
źródło
5
+1 za kreatywność, ale -1 za oszukiwanie.
Johannes H.
1
Ha, ale czy „gwarantuje się, że zacznie od nowa”, jeśli nigdy się nie skończy?
Jason C
Dlatego powiedziałem, że prawdopodobnie łamię zasadę. To filozoficzne piękno nieskończoności można założyć, że po tym wszystko może się zdarzyć. Tak działa również maszyna Turinga.
drobnoustrój
1
-100, ponieważ nie popieram wygrania własnego konkursu, szczególnie pod względem technicznym, ale +101, ponieważ oczekiwanie na jego ponowne uruchomienie jest najlepszą wymówką zwlekającą z odwlekaniem.
Jason C
Wiesz, a następnie while true; do sleep 1; donepikuje, prawda?
jo
2

Grzmotnąć

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

Zapisz to jako repeat.sh w katalogu / i daj mu uprawnienia do wykonania. Można go zabić, usuwając plik

Działa to poprzez umieszczenie wpisu w crontab, aby uruchomić go 1 minutę później.

g. gniazdo
źródło
2

Visual Base 6 :)

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

Aby uruchomić, utwórz nowy projekt, dodaj moduł z tym kodem, ustaw obiekt startowy na „Sub Main”, skompiluj, a następnie uruchom plik wykonywalny.


Bardziej czytelna wersja:

Sub Main()
    Call Shell("cmd ping 1.1.1.1 -n 1 -w 3000 > nul && """ & App.Path & "\" & App.EXEName & """")
End Sub
Szczoteczka do zębów
źródło
VB6 to VB prawdziwego mężczyzny. Ostatni w swoim rodzaju!
Jason C
1

HTML / JAVASCRIPT

PLIK HTML a.html

<script>window.location = "a.html"</script>
Clyde Lobo
źródło
1

Grzmotnąć

Dłużej niż to musi być, ale jestem zmęczony i nie obchodzi mnie to :)

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

Powiedziałeś, że musi się zrestartować po zakończeniu, nie powiedziałeś konkretnie, że musi to robić wielokrotnie lub w nieskończoność. Powiedziałeś też, że nigdy nie powinny działać dwie instancje naraz ... nigdy nie będzie. ;)

Jest na to wiele sposobów. Moim osobistym faworytem byłoby zrobienie czegoś takiego jak wysłanie pakietu gdzieś daleko, a następnie (za pomocą dowolnej liczby metod), aby reakcja wyzwoliła proces.

Ian Wizard
źródło
Technicznie sleepproces ten uruchamia się ponownie po zakończeniu
pastebin.com slash 0mr8spkT
Jeśli program jest programem, który uruchamia się ponownie to samo , to zakłada się, że ma to robić w nieskończoność - w przeciwnym razie jest ona ponownym uruchomieniu coś innego, że nie jest sama.
Jason C
@Jason C: Bez zbytniego filozofowania, na tyle, na ile to możliwe, sam się restartuje. Możemy dyskutować, jak skomplikowane to musi być naprawdę uruchomić go siebie , ale myślę, że to dobrze poza to, co autor miał na myśli. Chociaż jeśli chcesz, aby naprawdę się zrestartował, prawdopodobnie byłoby to coś, co używa goto, JMP lub jakiejkolwiek konstrukcji oferowanej przez Twój język, aby wrócić do początku, więc samo się „restartuje”. W przeciwnym razie po prostu wykonuje coś, co jest wyraźnie podobne do siebie. Ale wtedy ktoś prawdopodobnie podejmie problem, że nie jest to naprawdę ponowne uruchomienie. Więc dygresję.
Ian Wizard
1

Android: Alarm uruchomi ponownie Aktywność po 1 sekundzie

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();
}

}
drut67
źródło
1

Środowisko C + MPI

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");
    }
}

Musisz mieć zainstalowany OpenMPI lub inną implementację MPI. Połącz z

mpicc -o mpifork mpifork.c

Teraz, gdy o tym myślę, nie ma powodu, aby używać mpicc - gcc lub innego kompilatora, który zadziała. Musisz tylko mieć mpirun.

gcc -o mpifork mpifork.c

Aby go uruchomić, prawdopodobnie powinieneś podać pełną nazwę ścieżki i listę hostów. Na przykład dodałem niektóre wpisy w / etc / hosts, które wskazywały na localhost i uruchomiłem to w następujący sposób:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

Plik wykonywalny musi znajdować się w tym samym katalogu na dowolnym komputerze, na którym chcesz go uruchomić.


Zasadniczo bierze to listę hostów podaną w wierszu poleceń, wybiera jeden z hostów i uruchamia plik wykonywalny na hoście docelowym z tymi samymi argumentami. Jeśli wszystko pójdzie idealnie, mpirun będzie wywoływał się w kółko na różnych komputerach (lub na tym samym komputerze, jeśli podasz tylko „localhost”. Sam plik wykonywalny (mpifork) kończy działanie - po wywołaniu przestaje działać execvpna pierwszej maszynie).

Jeśli chcesz być zły, możesz zamiast tego uruchomić to na każdym komputerze, dołączając pełną listę hostów, która znajduje się w wierszu poleceń args. To odrodziłoby kopię samego siebie na każdej maszynie, w kółko - widełkową klaster.

Jednak w tej formie jestem pewien, że spełnia to zasady.

milinon
źródło
1

JavaScript

Bez „wchodzenia do sieci”, gdy nie jest to konieczne :-) Planowanie pętli zdarzeń JavaScript pozwala nam bardzo łatwo pisać programy, które spełniają podane wymagania:

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

Spowoduje to „ponowne uruchomienie” programfunkcji w tempie 10 razy na sekundę. Ze względu na naturę JavaScript jest zagwarantowane, że w tym samym czasie uruchomione zostanie tylko jedno zadanie, i nie „restartuje środowiska” jak w „przeładowaniu strony”.

Bergi
źródło
0

Montaż x86

Nie jestem do końca pewien, czy spełnia to twoje kryteria, ponieważ nie odradza się nowy proces, ale i tak jest.

Program wyświetli okno komunikatu, przydzieli część pamięci, skopiuje własną sekcję kodu do przydzielonej pamięci, a następnie przeskoczy do tej lokalizacji, rozpoczynając cykl od początku. Powinien działać, dopóki malloc się nie powiedzie.

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'

Kompilowany z FASM.

Oscar
źródło
4
Ponieważ w Twoim programie jest wywoływanie nowo skopiowanego kodu, więc technicznie twój program nigdy się nie zakończył.
drobnoustrój
6
Z punktu widzenia niskiego poziomu to samo można powiedzieć o wszystkich programach tutaj. :-)
Brian Knoblauch
@BrianKnoblauch Nie zgadzam się. Najciekawsze odpowiedzi tutaj wydają się modyfikować środowisko systemowe, tak aby nowa kopia procesu została uruchomiona jakiś czas po zabiciu pierwszego. Na przykład sądzę, że utworzenie chronicznego zadania w celu uruchomienia procesu w przyszłości byłoby dobrym sposobem na całkowite umieranie procesu, a następnie jego ponowne uruchomienie.
Kevin - Przywróć Monikę
2
@BrianKnoblauch Nie bardzo. Proces jest konstrukcją systemu operacyjnego (która obecnie - podobnie jak od czasu pojawienia się trybu chronionego w 286 w 1982 r. - jest również wspierana sprzętowo przez wirtualne przestrzenie adresowe i chronioną pamięć). Kiedy to się skończy, wszystkie te informacje znikną. Chociaż nie zostało to wyraźnie określone w wyzwaniu, rozumiem ducha wyzwania, że ​​„ponowne uruchomienie” oznacza, że ​​przypisano nowy identyfikator procesu.
Jason C.
Cóż, dałbym +1, jeśli uda ci się uwolnić pamięć po drodze (proszę ping mnie @ kiedy to zrobisz, ponieważ prawdopodobnie nie będę mieć na to oko).
jo
0

Linux upstart init

Biorąc pod uwagę najściślejsze czytanie pytania, myślę, że jest to niemożliwe. W gruncie rzeczy wymaga spontanicznego uruchomienia programu bez pomocy innych uruchomionych programów.

Istnieją pewne ati chronoparte na odpowiedziach odpowiedzi, ale przy najsurowszym czytaniu, atdi anacronsą to dodatkowe programy, które działają cały czas, więc mogą zostać zdyskwalifikowane.

Podobnym podejściem, ale nieco niższym poziomem jest używanie Linuksa init. Jako root dodaj ten plik .conf do /etc/init/:

opis „na zawsze”

zacznij na poziomie pracy [2345]
stop na poziomie pracy [! 2345]

odrodzenie

exec sleep 10

Więc mam init ponownie przeczytaj jego pliki .conf:

sudo telinit 5

Rozpocznie się sleep proces, który będzie trwał 10 sekund, a następnie zakończy się. initodrodzi się sleeppo wykryciu, że poprzedni zniknął.

Oczywiście jest to nadal używany initjako program dodatkowy. Można argumentować, że initjest to logiczne rozszerzenie jądra i woli zawsze będzie dostępne w dowolnym systemie Linux.

Jeśli nie jest to do zaakceptowania, myślę, że następną rzeczą do zrobienia na niższym poziomie byłoby stworzenie modułu jądra, który odradza proces przestrzeni użytkownika (nie jestem pewien, jak to jest łatwe). Tutaj można argumentować, że jądro nie jest procesem, a zatem nie programem (dodatkowym). Z drugiej strony jądro jest samodzielnym programem z punktu widzenia procesora.

Cyfrowa trauma
źródło
-1

TI-BASIC: 5 znaków

nazwać prgmA

:prgmA
scrblnrd3
źródło
Mogę policzyć 6 znaków. Czy jest coś specjalnego w liczeniu rozmiaru programu TI-BASIC?
pastebin.com slash 0mr8spkT
To :dopiero początek symbolu linii, gdy programujesz w TI-basic. To nie jest coś, co piszesz, jest tylko w edytorze.
scrblnrd3
Rozumiem, dziękuję za informację
pastebin.com slash 0mr8spkT
Czy to nie jest rekurencyjne wywołanie? Spróbuj zwiększyć Awartość i wykorzystaj jej wartość jako przypadek podstawowy, w końcu zobaczysz, że stopniowo się zmienia.
ζ--
Cóż, wszystkie zmienne są globalne w ti-basic, więc nie jestem pewien. Może być
scrblnrd3