Un programma che termina ma non finisce mai [chiuso]


35

Scrivi un programma che si riavvia al termine.

Non ci dovrebbero essere più di un'istanza del programma in esecuzione contemporaneamente. Nemmeno per un minimo momento.

È possibile ignorare qualsiasi istanza avviata manualmente dall'utente durante il ciclo. Ma il tuo codice non dovrebbe farlo nel tuo ciclo di riavvio.

Il programma può iniziare dopo un certo periodo di tempo, purché sia ​​garantito che si riavvii.

L'unico modo per interrompere il ciclo è interrompere il processo.

La soluzione non dovrebbe comportare il riavvio dell'ambiente (in cui il programma è in esecuzione, include sistema operativo, macchina, VM, shell ecc.). Solo il tuo programma è autorizzato a riavviare.


11
Non è proprio quello che execfa Linux?
mniip,

11
Sono un po 'pigro per scriverlo ora, ma la mia presentazione sarebbe (per Windows): "Modifica il registro in modo che il mio programma si avvii all'avvio. Esegui shutdown -r -t 0 -f".
Cruncher,

3
Uccidere il processo però non ucciderà il tuo ciclo.
microbian

19
Ho appena realizzato: se voglio scrivere un virus e non so come, potrei 1) andare su StackOverflow, chiedere come. Ottieni odio da tutti e probabilmente la domanda sarà chiusa. Oppure 2) Vai al codice golf, chiedi agli altri come lo farebbero. Ottieni una manciata di risposte creative tra cui scegliere e la domanda è così popolare che arriva nell'elenco "caldo" della rete. Mua ah ah ah ah.
Rumtscho,

5
@rumtscho Sai, questa è una buona strategia generale. Ok ragazzi, per la mia prossima sfida, vediamo chi può scrivere il firmware più piccolo per il dispositivo prototipo seduto sulla mia scrivania che soddisfa tutti i requisiti nel documento collegato. Per rendere più piccante, questo deve essere fatto entro le 8:00 di lunedì mattina. Partire!
Jason C,

Risposte:


50

Bash script, 3 caratteri (il più breve, forse il più elegante, anche se certamente controverso)

$0&

Posiziona semplicemente una nuova istanza di se stesso in background (nuovo processo), quindi si chiude. È probabile che la nuova istanza rimanga nella coda di esecuzione dello scheduler fino al completamento dell'istanza precedente.

Avviso: è difficile kill, poiché il PID è in continua evoluzione. Rinominare temporaneamente il file di script è probabilmente il modo più semplice per interrompere il ciclo.

Si presuppone un sistema single-core. Ovviamente questo non è realistico con Linux su hardware bare metal moderno, ma è facilmente configurabile quando si esegue in una VM. Probabilmente potremmo ottenere un trucco simile usando taskset, ma ciò ridurrebbe l'impatto della soluzione a 3 caratteri.

Questa risposta piega un po 'le regole in quanto applica un significato specifico di "correre". Ci saranno momenti in cui il nuovo processo è stato modificato fork()e il vecchio processo è ancora in vita, ovvero potrebbe essere possibile osservare più di un PID. Tuttavia, il nuovo processo verrà inserito nella coda di esecuzione dello scheduler Linux per attendere i cicli della CPU, mentre il processo esistente continuerà a essere eseguito. A questo punto tutto ciò che deve essere fatto dal processo esistente è di per bashexit(). Ciò richiede una quantità limitata di tempo, anche se sono abbastanza sicuro che sarà fatto molto prima che venga fatto l'attuale quantum timeslice / scheduler. Le prove a supporto sono il fatto che si bashavvia e si arresta in 2ms sulla mia VM:

$ time bash -c:

0m0.002s reali
utente 0m0.000s
sys 0m0.000s
$ 

Ulteriori prove a sostegno del fatto che il nuovo processo non viene effettivamente eseguito fino a quando non viene eseguito il processo precedente possono essere visualizzati stracenell'output:

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

Nell'output, vediamo che il processo originale ha PID 6929. Possiamo vedere la fork()chiamata (in realtà clone()), che restituisce un nuovo PID di 6930. A questo punto ci sono 2 PID, ma solo 6929 è attualmente in esecuzione:

6929 12: 11: 01.031398 clone (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 letto (255, "", 4) = 0
6929 12: 11: 01.031907 exit_group (0) =?
6930 12: 11: 01.032016 chiuso (255) = 0
6930 12: 11: 01.032052 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0

straceUscita completa qui.

Possiamo vedere che 6930 non emette chiamate di sistema fino a quando 6929 non è stato completamente completato. È ragionevole supporre che ciò significhi che 6930 non funziona affatto fino a quando non viene eseguito 6929. L' perfutilità sarebbe il modo migliore per dimostrarlo.


21
"riavvia ..., quindi esce", quindi più di un'istanza sono in esecuzione contemporaneamente?
microbian

4
"... su single core" - sì, lo immagino anche io. Su molti core, potresti essere in grado di vederne molti.
blabla999,

3
Se questo è stato taggato code-golf, allora vincerà sicuramente! +1
John Odom,

3
@DigitalTrauma Stai facendo grandi assunzioni su quanto tempo impiega bash per spegnersi. top non ti dice nulla - si aggiorna solo una volta ogni pochi (decine di) secondi ma stai generando molti processi al secondo.
David Richerby,

2
@DavidRicherby - hai perfettamente ragione - topnon è lo strumento giusto da usare qui. Tuttavia, vedo che ci time bash -c :vogliono solo 2ms sulla mia macchina virtuale Ubuntu, quindi non penso che sia irragionevole aspettarsi bashdi completare il suo arresto prima che sia fatto il suo quantum di programmazione.
Trauma digitale

26

Soluzione 1

PHP, 32 caratteri

Invia l'intestazione e quindi si interrompe. Dopo 3 secondi, la pagina viene ricaricata.

file a.php

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

Questo può essere interrotto terminando l'esecuzione della pagina prima che vengano inviate le intestazioni o semplicemente uccidendo il browser.


Soluzione 2

PHP, 2 pagine

Consideriamo i due file due programmi diversi. I due file si trovano nella stessa cartella.

file a.php

header("Location:b.php");

file b.php

header("Location:a.php");

La chiusura di una delle pagine prima dell'invio delle intestazioni termina il programma (anche l'uccisione del browser funziona).

Ecco lo stesso programma in

ASP.NET

file a.aspx

Response.Redirect("b.aspx")

file b.aspx

Response.Redirect("a.aspx")

1
Questa è una bella soluzione. Spero che altri arrivino con risposte diverse da questa. Ecco perché l'ho tenuto come concorso di popolarità.
microbian

Se la tua risposta di ricarica di 3 secondi è valida o meno, la lascio agli esperti di php. Penso che potrebbe essere valido, perché è il browser che non sta aspettando il tuo php (non sono un esperto).
microbian

1
Mentre tecnicamente PHP viene eseguito come modulo di un server Web e il tuo server Web non si è riavviato, penso che sia valido se consideri un file .php come uno script e lo script viene eseguito più volte.
TwiNight,

@TwiNight Grazie per il feedback, lo apprezzo :)
Vereos,

2
Per la tua seconda soluzione, il browser non rileverebbe un ciclo di reindirizzamento e si fermerebbe da solo? thedan1984.com/wp-content/uploads/2012/02/…
Ajedi32

19

sh

echo $PWD/$0 | at tomorrow

Funzionerà su qualsiasi sistema conforme a Posix.

Per ucciderlo, eliminare il file o utilizzare atrm.


17

bash

exec "$0"

execsostituisce la shell senza creare un nuovo processo. Questo assicura che non ci possa essere una seconda istanza.


1
Meglio metterlo dentro ~/.bash_profile!
yegle,

@yegle: $0è il -bashmomento in cui .bash_profileproviene, quindi ciò comporterebbe solo un errore di sintassi.
Dennis,

Oops, hai ragione.
yegle

exec ${0##-}nelle ~/.bash_profileopere :-)
yegle

14

Utilità di pianificazione di Windows (nativo)

C ++. Un incubo di programmazione COM. Soddisfa tutti i requisiti delle sfide.

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

}

Compilare con MSVC (o MinGW GCC se si hanno tutte le dipendenze).

Il programma avvierà e registrerà un'attività una tantum con l'utilità di pianificazione di Windows per avviarsi 5 secondi dopo (Pannello di controllo -> Strumenti di amministrazione -> Utilità di pianificazione per visualizzare, l'attività è denominata "Riavvio"). Il programma si fermerà per 5 secondi per darti la possibilità di ucciderlo prima che crei l'attività.

Requisiti della sfida:

  • Si riavvia al termine. Sì. L'attività è pianificata appena prima dell'uscita dal programma.

  • Non più di un'istanza del programma in esecuzione contemporaneamente. Sì. Il programma si chiude completamente e non viene eseguito per 5 secondi. Viene avviato dallo scheduler.

  • È possibile ignorare qualsiasi istanza avviata manualmente dall'utente durante il ciclo. Sì, come effetto collaterale dell'utilizzo di un nome di attività costante.

  • Finché è garantito che ricomincia. Sì, a condizione che l'Utilità di pianificazione sia in esecuzione (è in una configurazione Windows standard).

  • L'unico modo per interrompere il ciclo è interrompere il processo. Sì, il processo può essere interrotto durante la finestra di 5 secondi mentre è in esecuzione. Il programma elimina l'attività prima del ritardo di 5 secondi, uccidendola in questo momento non lascerà un'attività vagante nello scheduler.

  • La soluzione non dovrebbe comportare il riavvio dell'ambiente Sì.

A proposito, se qualcuno si è mai chiesto perché le applicazioni Windows fossero così instabili (prima dell'avvento di .NET e C #), questo è uno dei motivi. La quantità di gestione degli errori richiesta (se l'ho inclusa), la gestione delle risorse e la verbosità creano situazioni molto inclini agli errori se un programmatore è anche il minimo pigro (il codice sopra è estremamente pigro).

Un'alternativa molto più semplice e più breve è invocare schtasks.exe. Ho presentato una versione con quella anche in uno script .BAT .


13

BBC BASIC - un omaggio a Snow Patrol

Emulatore su bbcbasic.co.uk

Questo è un po 'diverso. Stampa un verso della canzone "Run" e suona un arpeggio degli accordi in modo da poter cantare insieme. È stato ispirato dal fatto che il comando da eseguire (e quindi l'ultima riga del programma) è ovviamente ESEGUITO.

Tutte le variabili vengono cancellate all'inizio del programma, quindi ci vuole il colore dello schermo lasciato dalla precedente iterazione per decidere quale verso stampare successivamente.

    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 (montaggio di 4 diverse schermate)

enter image description here


+1 per la soluzione colore come alternativa "memoria condivisa".
Johannes H.

11

HTML / JavaScript:

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

Il codice innesca la distruzione della pagina su cui è in esecuzione, quindi la ricostruzione di un'altra istanza di se stessa quando il browser carica di nuovo la pagina.

AFAIK, l'unica via d'uscita è uccidere la scheda in cui è in esecuzione la pagina.

MODIFICA: come da richiesta popolare, un codice HTML5 valido:

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

@JasonC Non sono d'accordo. Penso che le pagine ragionevoli dovrebbero essere conformi alle specifiche, ma i contest di popolarità dovrebbero essere ragionevoli, vero? : D così +1, mi piace molto questo.
giovedì

10

C

Questo programma agisce come un sacco di malware. Poco prima della sua chiusura, crea uno script di shell nella directory / tmp. Si avvia per avviare lo script di shell, che consente di chiudere il programma originale e annullare il PID originale. Dopo un breve periodo di tempo (2 secondi) lo script della shell avvia un nuovo processo con il programma. Per brevità, la posizione del programma è cablata come '/ 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]);
}

Esiste sempre un solo processo "infinito" alla volta. Ogni nuovo processo ottiene un nuovo PID. Il modo più semplice per eliminarlo è eliminare l'eseguibile. Se vuoi renderlo più maligno, puoi copiare sia l'eseguibile che lo script per assicurarti che ci siano più copie sul programma su disco in qualsiasi momento.


1
Mi aspetto di vedere risposte più innovative. Vedi i commenti per domande su "programmi integrativi". Per me, un programma di integratori è solo una parte del tuo programma.
microbian

4
Forking significa che avrai due istanze del processo in esecuzione contemporaneamente, anche se stanno facendo cose diverse.
Barry Fruitman,

@BarryFruitman facile da evitare, però, utilizzando davvero due diversi eseguibili. È valido quindi, ma molto meno elegante.
Johannes H.

Suppongo che potresti usare system()se le regole non contano un fork + exec /bin/shcome programma supplementare.
Jason C,

10

Perl

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

Lo script emette un comando di sistema per uccidere se stesso e reindirizzare il risultato in un'altra istanza di se stesso. L'interprete Perl è usato per uccidere, per motivi multipiattaforma.

Ferma la follia eliminando la sceneggiatura.


7

Atari 8-bit Basic

1L.:R.

Tokenize per:

1 LIST : RUN

Internamente sta cancellando le strutture interne, essenzialmente cancellando il programma, prima di eseguirlo di nuovo dall'elenco.

Questo è fondamentalmente diverso da:

1L.:G.1

Che tokenizza a:

1 LIST : GOTO 1

Questo è un ciclo infinito di base. Quando li esegui, vedi la differenza di velocità (la prima è più lenta).


Non sono del tutto chiaro il motivo per cui la "lista" durante l'esecuzione del programma eliminerebbe qualsiasi struttura interna. Penso che l'Atari abbia un buffer di tastiera, quindi si potrebbe elencare il programma, riempire i tasti per eseguirlo e fare un "nuovo" con il cursore posizionato per "ridigitare".
supercat,

@supercat - LIST no, RUN lo fa.

Secondo questa logica, si potrebbe omettere la "LISTA". D'altra parte, se il programma riempiva il buffer della tastiera, con alcuni ritorni a capo, metti "NEW" seguito dal programma e "RUN" nei punti giusti sullo schermo, ospita il cursore ed esce, si cancellerebbe davvero e digitare nuovamente se stesso automaticamente.
supercat,

@supercat - senza il LIST, non lo vedresti in esecuzione. Ho scelto LISTperché ha l'input più breve L.. Mi piace l'idea di metterlo in un buffer di tastiera, è certamente abbastanza breve!

Ricordo correttamente che l'Atari, come le macchine Commodore, legge il testo dallo schermo quando si preme Return? Quanto è grande il buffer della tastiera? Su VIC-20 e C64, sono dieci byte. Un programma che fa abbastanza scherzi per caricare il buffer della tastiera probabilmente non si adatterebbe al buffer della tastiera, ma ho scritto programmi che si modificerebbero stampando le modifiche sullo schermo seguite da RUN, e aggiungendo alcune Returnsequenze di tasti. Queste cose erano particolarmente utili su 64 poiché non aveva il INcomando [IIRC] che Atari ha per unire le linee in un programma.
supercat,

5

Su un mainframe IBM che esegue z / OS, si esegue un'utilità che copia un set di dati (file) in un altro set di dati (file). L'input è l'origine del JCL (Job Control Language) che è stato inviato per farlo funzionare. L'output è il lettore interno (INTRDR). Dovrai anche assicurarti che il tuo sistema non consenta l'esecuzione di più nomi di lavoro identici. Buono a usare una classe di lavoro che ha un solo iniziatore (luogo in cui un JOB può essere eseguito in batch).

Non ci sono PID coinvolti (in z / OS), quindi fallisce il set di sfide.

Si interrompe il processo drenando e / o irrigando. Se qualcosa è andato storto, svuotando e / o arrossando, imprecando, calciare, tentando un avvio a caldo e infine con un avvio a freddo o premendo il pulsante rosso grande (e sparando al programmatore).

Potrei aver esagerato lungo la strada, ma non provarlo al lavoro ...

Esempio usando SORT. I dettagli sulla scheda JOB dipendono molto dal sito. La politica del sito può vietare o impedire l'uso di INTRDR. Potrebbe essere richiesta una classe specifica per utilizzare INTRDR. Se la politica del tuo sito ne proibisce l'uso , non utilizzarlo meno che tu non voglia portare i tuoi effetti personali a fare una passeggiata in una scatola di cartone.

Sebbene ci siano buoni usi per INTRDR, non utilizzarlo per questo scopo . Non avrai nemmeno la possibilità di ottenere la tua scatola.

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

Altre utilità sono disponibili. Sarebbe anche facile fare un programma veloce, basta leggere un file, scrivere un file.

Se vuoi che un esempio di questo vada storto, prova: http://ibmmainframes.com/viewtopic.php?p=282414#282414

Il modo tradizionale di copiare un set di dati è utilizzare l'utilità IBM IEBGENER, come ugoren allude nel loro commento.

Tuttavia, oggigiorno, molti siti avranno IEBGENER "aliasato" su ICEGENER. Se possibile, ICEGENER utilizzerà il DFSORT di IBM (o il suo SyncSort rivale) per fare una copia, perché i prodotti SORT sono molto più ottimizzati per IE rispetto a IEBGENER.

Sto solo tagliando l'intermediario usando SORT.

Se lavori in un sito IBM Mainframe, conosci il formato della scheda JOB che dovresti usare. La scheda JOB minima è come ho mostrato, senza il commento. Il commento sarà importante, perché si potrebbe supporre che tu stia fornendo informazioni contabili, ad esempio. Il nome lavoro avrà probabilmente un formato specifico per il sito.

Alcuni siti vietano o impediscono l'uso di INTRDR. Sii consapevole.

Alcuni siti consentono l'esecuzione simultanea di più lavori con lo stesso nome. Sii consapevole.

Sebbene a meno che tu non sia un programmatore di sistema, non puoi impostare tale classe, dovresti cercare una classe che consenta un solo iniziatore. Con ciò, il processo è abbastanza sicuro, ma assicurati assolutamente che la classe funzioni come descritto. Test. Non con questo lavoro.

Se sei un programmatore di sistema, sai di non fare nulla al di fuori delle tue competenze. 'ha detto Nuff.

Con un lavoro con lo stesso nome consentito contemporaneamente e un solo iniziatore, questo sarà un flusso costante di inizio / fine lavoro successivo / fine lavoro successivo - fino a riempire lo spool (un'altra cosa negativa da fare) con l'output di migliaia di lavori (o numero di lavori esaurito). Guarda una console JES per i messaggi di avviso.

Fondamentalmente, non farlo. Se lo fai, non farlo su una macchina di produzione.

Con un po 'di ripassamento, prenderò in considerazione un'altra risposta su come farlo su un altro sistema operativo IBM Mainframe, z / VSE ... z / VSE utilizza JCL. z / OS utilizza JCL. Sono diversi :-)


L'idea sembra buona, ma non è una risposta. Mostraci il JCL - JOB, EXEC e DD - quindi sarà una risposta.
ugoren,

Non ho presentato un lavoro da molto tempo, quindi non sono sicuro di cosa farne. Se le parti mancanti sono solo personalizzazioni locali, quindi OK. Ma se nascondi delle cose per prevenire un abuso, allora decidi: pubblica la cosa vera o non pubblicare nulla. PS All'epoca usavamo IEBGENERsemplicemente copiare.
ugoren,

@ugoren Ulteriore aggiornamento, inclusa la spiegazione del perché IEBGENER non è stato selezionato per l'attività. La rimozione del testo del commento sull'istruzione JOB fornisce il JCL necessario per l'esecuzione, ma essendo JCL sufficiente dipende dagli standard del sito locale, affinché il lavoro funzioni o affinché il programmatore eviti di essere licenziato.
Bill Woodger,

4

Python (72 byte)

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

Potrebbe essere più piccolo, immagino. Innanzitutto, codificando il nome del file (anziché utilizzarlo __file__). Ma qui, puoi inserire questo codice in un file ed eseguirlo, qualunque sia il suo nome :)


Probabilmente puoi passare &&a &.
Hosch250,

1
Da quando è consentito, user2509848?
Rhymoid,

Bene, potresti iniziare rimuovendo lo spazio bianco ...
Ry

6
Dato che non è taggato code-golf , terrò il codice in questo modo :-)
Maxime Lorant,

4

Utilità di pianificazione di Windows (.BAT)

Script batch di Windows. Soddisfa tutti i requisiti delle sfide.

Per quanto posso vedere questa è l'unica soluzione di Windows finora che soddisfa tutti i requisiti e non ha dipendenze non standard (la mia altra soluzione è simile ma richiede la compilazione).

@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

Il programma si comporta in modo simile alla mia risposta C ++ / COM .

Il programma avvierà e registrerà un'attività singola con l'utilità di pianificazione di Windows per avviarsi fino a 60 secondi dopo (Pannello di controllo -> Strumenti di amministrazione -> Utilità di pianificazione per visualizzare, l'attività è denominata "Riavvio"). Il programma si fermerà per 5 secondi per darti la possibilità di ucciderlo prima che crei l'attività.

Utilizza l'interfaccia dell'utilità di pianificazione della riga di comando schtasks.exe . L'aritmetica nello script consiste nel calcolare gli offset di tempo mantenendo il tempo valido e nel formato HH: MM.

Requisiti della sfida:

  • Si riavvia al termine. Sì. L'attività è pianificata appena prima dell'uscita dal programma.

  • Non più di un'istanza del programma in esecuzione contemporaneamente. Sì. Il programma si chiude completamente e non funziona per ~ 60 secondi. Viene avviato dallo scheduler.

  • È possibile ignorare qualsiasi istanza avviata manualmente dall'utente durante il ciclo. Sì, come effetto collaterale dell'utilizzo di un nome di attività costante.

  • Finché è garantito che ricomincia. Sì, a condizione che l'Utilità di pianificazione sia in esecuzione e schtasks.exe sia presente (entrambi veri nelle configurazioni predefinite di Windows).

  • L'unico modo per interrompere il ciclo è interrompere il processo. Sì, il processo può essere interrotto durante la finestra di 5 secondi mentre è in esecuzione. Il programma elimina l'attività prima del ritardo di 5 secondi, uccidendola in questo momento non lascerà un'attività vagante nello scheduler.

  • La tua soluzione non dovrebbe comportare il riavvio dell'ambiente Sì.

Nota: a causa della limitata interfaccia della riga di comando, è necessario specificare il tempo di riavvio in minuti e l'attività non verrà riavviata sui laptop senza l'adattatore CA collegato (scusa).


3

Shell Unix

Non ho ancora visto molte soluzioni che si basano su un programma non correlato per riavviarlo. Ma questo è esattamente ciò per cui è at(1)stata creata l' utilità:

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

È davvero difficile avviare il programma, poiché viene eseguito solo una volta al minuto ed esce così rapidamente. Fortunatamente l' atq(1)utilità ti mostrerà che sta ancora andando:

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

E atrm(1)ti permetterà di interrompere il ciclo:

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

È possibile sostituire 1 minutecon 1 hour, o 1 week. O darlo 1461 daysper avere un programma che gira una volta ogni 4 anni.


2

PowerShell

Sto abusando (e forse infrangendo) la mia stessa regola.

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

Ci vuole una quantità infinita di tempo per riavviarsi.
Può essere ucciso uccidendo il processo host.

Aspetta e vedrai ;)


5
+1 per la creatività, ma -1 per barare.
Johannes H.

1
Ah, ma è "garantito che ricomincia" se non si ferma mai?
Jason C,

Ecco perché ho detto che probabilmente sto infrangendo la regola. È la bellezza filosofica dell'infinito che puoi supporre che dopo ciò possa succedere di tutto. Anche la macchina di Turing funziona in questo modo.
microbian

1
-100 perché non ti supporto a vincere il tuo contest, specialmente per un tecnicismo, ma +101 perché aspettare che si riavvii è la scusa di procrastinazione migliore di sempre.
Jason C,

Bene, sai, poi si while true; do sleep 1; donequilifica, vero?
giovedì

2

bash

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

Salvarlo come repeat.sh nella directory / e dargli il permesso di esecuzione. Può essere ucciso eliminando il file

Funziona inserendo una voce nel crontab per eseguirla 1 minuto dopo.


2

Visual Base 6 :)

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

Per eseguire, creare un nuovo progetto, aggiungere un modulo con questo codice, impostare l'oggetto di avvio su "Sottotitoli", compilare e quindi eseguire l'eseguibile.


Versione più leggibile:

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

VB6 è il VB di un vero uomo. L'ultimo del suo genere!
Jason C,

1

HTML / JAVASCRIPT

FILE HTML a.html

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

1

bash

Più lungo di quanto deve essere, ma sono stanco e non mi interessa :)

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

Hai detto che deve riavviarsi quando finisce, non hai detto specificamente che doveva farlo ripetutamente o indefinitamente. Inoltre, hai detto che non dovrebbe mai avere due istanze in esecuzione contemporaneamente ... non lo farà mai. ;)

Ci sono molti modi per farlo. Il mio preferito personale sarebbe quello di fare qualcosa come inviare un pacchetto da qualche parte distante, e quindi (tramite un numero qualsiasi di metodi), avere la risposta innescare il processo.


Tecnicamente, il sleepprocesso si riavvia al termine
pastebin.com slash 0mr8spkT

Se il programma è un programma che riavvia , quindi è implicito che ha a che fare in modo indefinito - altrimenti il riavvio qualcos'altro che non è di per sé.
Jason C,

@Jason C: Senza diventare troppo filosofico, nella misura del possibile, si riavvia da solo. Potremmo discutere su quanto debba essere complesso riavviare se stesso , ma penso che sia ben al di là di ciò che intendeva l'autore. Tuttavia, se vuoi che si riavvii davvero da solo, probabilmente sarebbe qualcosa che usa goto, o JMP, o qualunque costrutto il tuo linguaggio possa offrire, per tornare all'inizio, quindi si "riavvia" da solo. Altrimenti, sta semplicemente eseguendo qualcosa che è distintamente simile a se stesso. Ma allora qualcuno probabilmente metterà in discussione il fatto che non è davvero il riavvio. Quindi sto divagando.
Ian Wizard,

1

Android: un allarme riavvierà l'attività dopo 1 secondo

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

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

Devi avere OpenMPI o qualche altra implementazione MPI installata. Compila con

mpicc -o mpifork mpifork.c

Ora che ci penso, non c'è ragione per cui devi usare mpicc - gcc o qualunque compilatore funzionerà. Devi solo avere il Mpirun.

gcc -o mpifork mpifork.c

Per eseguirlo, dovresti probabilmente includere il nome completo del percorso e includere un elenco di host. Ad esempio, ho aggiunto alcune voci in / etc / hosts che puntavano a localhost, e l'ho eseguito in questo modo:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

L'eseguibile deve trovarsi nella stessa directory su qualsiasi macchina su cui si desidera eseguirlo.


In sostanza, questo prende un elenco di host forniti sulla riga di comando, seleziona uno degli host e avvia l'eseguibile sull'host di destinazione con gli stessi argomenti. Se tutto funziona alla perfezione, mpirun si chiamerà più e più volte su macchine diverse (o sulla stessa macchina se fornisci solo 'localhost'. L'eseguibile stesso (mpifork) termina - dopo aver chiamatoexecvp , non viene più eseguito sulla prima macchina.

Se vuoi essere malvagio, puoi invece effettuare questo lancio su ogni macchina, includendo l'elenco completo degli host che viene fornito nella riga di comando inargs . Ciò genererebbe di nuovo una copia di se stesso su ogni macchina, più e più volte: un forkbomb a grappolo.

Tuttavia, in questa forma, sono abbastanza sicuro che questo soddisfi le regole.


1

JavaScript

Senza "andare in rete" quando non è necessario :-) La programmazione del loop degli eventi di JavaScript ci consente di scrivere programmi che soddisfano i requisiti indicati molto facilmente:

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

Questo "riavvia" la programfunzione ad un ritmo di 10 volte al secondo. È garantito dalla natura JavaScript che verrà eseguita una sola attività contemporaneamente e non "riavvia l'ambiente" come in "ricaricare la pagina".


0

Assemblaggio x86

Non del tutto sicuro che questo si adatta ai tuoi criteri in quanto non genera un nuovo processo, ma qui è comunque.

Il programma mostrerà una finestra di messaggio, allocherà un po 'di memoria, copierà la propria sezione di codice nella memoria allocata, quindi salterà in quella posizione ricominciando il ciclo. Dovrebbe funzionare fino a quando malloc fallisce.

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'

Compilato con fasmo.


4
Dal momento che fa parte del tuo programma chiamare il codice appena copiato, quindi tecnicamente il tuo programma non è mai finito.
microbian

6
Da un punto di vista di basso livello, lo stesso si potrebbe dire di tutti i programmi qui. :-)
Brian Knoblauch,

@BrianKnoblauch Non sono d'accordo. Le risposte più interessanti qui sembrano modificare l'ambiente di sistema in modo che una nuova copia del processo venga avviata qualche tempo dopo che il primo è stato ucciso. Ad esempio, penso che la creazione di un lavoro cronologico per eseguire il processo in futuro sarebbe un buon modo per lasciare che il processo muoia completamente, quindi venga riavviato.
Kevin - Ripristina Monica il

2
@BrianKnoblauch Non proprio. Un processo è un costrutto del sistema operativo (che oggigiorno - come dall'avvento della modalità protetta nel 286 nel 1982 - è anche supportato dall'hardware tramite spazi di indirizzi virtuali e memoria protetta). Quando finisce, tutte quelle informazioni scompaiono. Sebbene non sia stato esplicitamente dichiarato nella sfida, prendo lo spirito della sfida nel senso che il "riavvio" implica l'assegnazione di un nuovo ID processo.
Jason C,

Bene, darei +1 se riuscissi a liberare la memoria sulla strada (per favore fammi un rumore metallico @una volta che riesci, poiché probabilmente non lo terrò d'occhio).
giovedì

0

Linux startstart init

Data la lettura più rigorosa della domanda, penso che sia impossibile. In sostanza, si chiede che un programma inizi spontaneamente con l'aiuto di nessun altro programma in esecuzione.

Ci sono alcuni at e chronbasati su risposte, ma con la lettura più rigorosa, atdeanacron sono programmi complementari che sono in esecuzione tutto il tempo, in modo che possano essere squalificati.

Un approccio correlato, ma un livello leggermente inferiore è quello di usare Linux init. Come root, aggiungi questo file .conf a/etc/init/ :

descrizione "per sempre"

start on runlevel [2345]
stop on runlevel [! 2345]

respawn

exec sleep 10

Quindi initrileggi i suoi file .conf:

sudo telinit 5

Questo avvierà un sleepprocesso che durerà per 10 secondi, quindi uscirà. initrinascerà quindi sleepquando rileva che il precedente è scomparso.

Ovviamente questo sta ancora usando initcome programma supplementare. Si potrebbe obiettare che si inittratta di un'estensione logica del kernel e sarà sempre disponibile in qualsiasi Linux.

Se ciò non è accettabile, suppongo che la prossima cosa di livello inferiore da fare sarebbe quella di creare un modulo del kernel che risorga un processo di spazio utente (non sono sicuro di quanto sia facile). Qui si può sostenere che il kernel non è un processo e quindi non un programma (supplementare). D'altra parte, il kernel è un programma a sé stante, dal punto di vista della CPU.


-1

TI-BASIC: 5 caratteri

chiamalo prgmA

:prgmA

Posso contare 6 caratteri. C'è qualcosa di speciale nel contare le dimensioni del programma TI-BASIC?
pastebin.com barra 0mr8spkT

Il :è solo l'inizio di simbolo di una linea ogni volta che si programma in TI-base. Non è qualcosa che scrivi, è solo lì nell'editor.
scrblnrd3,

Vedo, grazie per le informazioni
pastebin.com barra 0mr8spkT

Quella invocazione ricorsiva non è? Prova ad incrementare Ae usare un valore come caso base, alla fine lo vedrai uscire.
ζ--

Bene, tutte le variabili sono globali in ti-basic, quindi non ne sono sicuro. Può essere
scrblnrd3,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.