Un programa que termina pero nunca termina [cerrado]

35

Escriba un programa que se inicie nuevamente cuando finalice.

No debe haber más de una instancia del programa ejecutándose al mismo tiempo. Ni siquiera por el más mínimo momento.

Puede ignorar cualquier instancia que el usuario inicie manualmente durante su ciclo. Pero su código no debería hacerlo en su ciclo de reinicio.

El programa puede comenzar después de cualquier cantidad de tiempo, siempre y cuando se garantice que se inicia nuevamente.

La única forma de detener el ciclo es matar el proceso.

Su solución no debe implicar el reinicio del entorno (en el que se ejecuta el programa, incluye SO, máquina, VM, shell, etc.). Solo su programa puede reiniciar.

microbiano
fuente
11
¿No es esto lo que exechace en Linux?
mniip
11
Soy un poco flojo para escribirlo en este momento, pero mi envío sería (para Windows): "Editar el registro para que mi programa se inicie al inicio. Ejecutar shutdown -r -t 0 -f".
Cruncher
3
Sin embargo, matar el proceso no matará tu ciclo.
microbio
19
Me acabo de dar cuenta: si quiero escribir un virus y no sé cómo, podría 1) ir a StackOverflow y preguntar cómo. Obtenga el odio de todos y probablemente la pregunta se cerrará. O 2) Vaya a code golf, pregunte a otros cómo lo harían. Obtenga un puñado de respuestas creativas para seleccionar, y la pregunta es tan popular que se incluye en la lista "hot" de toda la red. Mua, ja, ja, ja, ja.
rumtscho
55
@rumtscho Sabes, esa es una buena estrategia general. Ok chicos, para mi próximo desafío, veamos quién puede escribir el firmware más pequeño para el dispositivo prototipo sentado en mi escritorio que cumple con todos los requisitos del documento vinculado. Para darle más sabor, esto debe hacerse antes de las 8 de la mañana del lunes. ¡Ir!
Jason C

Respuestas:

50

Bash script, 3 caracteres (el más corto, posiblemente el más elegante, aunque ciertamente controvertido)

$0&

Simplemente coloca una nueva instancia de sí misma en segundo plano (nuevo proceso), luego se cierra. La nueva instancia probablemente permanecerá en la cola de ejecución del planificador hasta que se complete la instancia anterior.

Advertencia: esto es difícil kill, ya que el PID cambia continuamente. Cambiar el nombre temporalmente del archivo de script es probablemente la forma más sencilla de romper el ciclo.

Se supone un sistema de un solo núcleo. Por supuesto, esto no es realista con Linux en hardware moderno de metal desnudo, pero es fácilmente configurable cuando se ejecuta en una VM. Probablemente podríamos lograr un truco similar usando taskset, pero eso reduciría el impacto de la solución 3-char.

Esta respuesta dobla las reglas un poco porque aplica un significado específico de "correr". Habrá momentos en los que el nuevo proceso ha sido fork()editado y el proceso anterior todavía está vivo, es decir, es posible observar más de un PID. Sin embargo, el nuevo proceso se colocará en la cola de ejecución del planificador de Linux para esperar los ciclos de la CPU, mientras que el proceso existente continuará ejecutándose. En este punto, todo lo que debe hacer el proceso existente es hacerlo por bashsí mismo exit(). Esto lleva una cantidad de tiempo finita, aunque estoy bastante seguro de que se hará mucho antes de que se realice el tiempo actual / quantum del planificador. La evidencia de respaldo es el hecho de que se bashinicia y se apaga en 2 ms en mi VM:

$ time bash -c:

0m0.002s reales
usuario 0m0.000s
sys 0m0.000s
PS 

La evidencia adicional de que el nuevo proceso en realidad no se ejecuta hasta que se realiza el proceso anterior se puede ver en la stracesalida:

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

En la salida, vemos que el proceso original tiene PID 6929. Podemos ver la fork()llamada (en realidad clone()), que devuelve un nuevo PID de 6930. En este punto, hay 2 PID, pero solo 6929 se está ejecutando actualmente:

6929 12: 11: 01.031398 clon (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 de lectura (255, "", 4) = 0
6929 12: 11: 01,031907 exit_group (0) =?
6930 12: 11: 01,032016 cerrar (255) = 0
6930 12: 11: 01,032052 rt_sigprocmask (SIG_SETMASK, [], NULL, 8) = 0

Llena stracede salida aquí.

Podemos ver que 6930 no emite ninguna llamada del sistema hasta 6929 está completamente hecho. Es razonable suponer que esto no significa 6930 publiquen hasta 6929 está hecho. La perfutilidad sería la mejor manera de demostrar esto.

Trauma digital
fuente
21
"se reinicia ..., luego se cierra", ¿entonces se están ejecutando más de una instancia al mismo tiempo?
microbio
44
"... en un solo núcleo" - sí, supongo que también. En un núcleo múltiple, es probable que pueda ver muchos.
blabla999
3
Si esto fue etiquetado código de golf, entonces esto definitivamente va a ganar! 1
John Odom
3
@DigitalTrauma Estás haciendo grandes suposiciones sobre cuánto tiempo toma bash para cerrarse. top no te dice nada: solo se actualiza una vez cada pocos (decenas de) segundos, pero estás generando muchos procesos por segundo.
David Richerby
2
@DavidRicherby, tiene toda la razón, topno es la herramienta adecuada para usar aquí. Sin embargo, veo que time bash -c :solo toma 2 ms en mi VM de Ubuntu, por lo que no creo que sea irrazonable esperar bashcompletar su apagado antes de que se complete su programación cuántica.
Trauma digital
26

Solución 1

PHP, 32 caracteres

Envía el encabezado y luego se detiene. Después de 3 segundos, la página se vuelve a cargar.

archivo a.php

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

Esto se puede detener al finalizar la ejecución de la página antes de que se envíen los encabezados, o simplemente matando el navegador.


Solución 2

PHP, 2 páginas

Vamos a considerar los dos archivos de dos programas diferentes. Los dos archivos se encuentran en la misma carpeta.

archivo a.php

header("Location:b.php");

archivo b.php

header("Location:a.php");

Terminar una de las páginas antes de que se envíen los encabezados termina el programa (matar el navegador también funciona).

Aquí está el mismo programa en

ASP.NET

archivo a.aspx

Response.Redirect("b.aspx")

archivo b.aspx

Response.Redirect("a.aspx")
Vereos
fuente
1
Esa es una buena solución. Espero que otros vengan con respuestas diferentes a esta. Por eso lo mantuve como un concurso de popularidad.
microbio
Si su respuesta de recarga de 3 segundos es válida o no, se la dejo a los expertos en php. Creo que podría ser válido, porque es el navegador el que está esperando, no tu php (no soy un experto).
microbio
1
Aunque técnicamente PHP se ejecuta como un módulo de un servidor web y su servidor web no se reinició, creo que es válido si considera un archivo .php como un script y el script se ejecuta varias veces.
TwiNight
@TwiNight Gracias por los comentarios, lo agradezco :)
Vereos
2
Para su segunda solución, ¿no detectaría el navegador un bucle de redireccionamiento y se detendría solo? thedan1984.com/wp-content/uploads/2012/02/…
Ajedi32
19

sh

echo $PWD/$0 | at tomorrow

Esto funcionará en cualquier sistema compatible con Posix.

Para eliminarlo, elimine el archivo o úselo atrm.

ecatmur
fuente
17

golpetazo

exec "$0"

execreemplaza el shell sin crear un nuevo proceso. Esto asegura que no pueda haber una segunda instancia.

Dennis
fuente
1
Mejor ponlo ~/.bash_profile!
yegle
@yegle: $0es -bashcuando .bash_profilese origina, por lo que eso solo daría como resultado un error de sintaxis.
Dennis
Vaya, tienes razón.
yegle
exec ${0##-}en ~/.bash_profileobras :-)
yegle
14

Programador de tareas de Windows (nativo)

C ++. Una pesadilla de programación COM. Cumple con todos los requisitos de desafío.

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

}

Compile con MSVC (o MinGW GCC si tiene todas las dependencias).

El programa se iniciará y registrará una tarea única con el programador de tareas de Windows para iniciarse 5 segundos después (Panel de control -> Herramientas administrativas -> Programador de tareas para ver, la tarea se llama "Reiniciar"). El programa hará una pausa de 5 segundos para darle la oportunidad de matarlo antes de que cree la tarea.

Requisitos de desafío:

  • Comienza de nuevo cuando termina. Sí. La tarea se programa justo antes de la salida del programa.

  • No más de una instancia del programa ejecutándose al mismo tiempo. Sí. El programa sale completamente y no se ejecuta durante 5 segundos. Lo inicia el planificador.

  • Puede ignorar cualquier instancia que el usuario inicie manualmente durante su ciclo. Sí, como efecto secundario del uso de un nombre de tarea constante.

  • Siempre y cuando esté garantizado que comience de nuevo. Sí, siempre que el Programador de tareas se esté ejecutando (está en una configuración estándar de Windows).

  • La única forma de detener el ciclo es matar el proceso. Sí, el proceso se puede eliminar durante la ventana de 5 segundos mientras se está ejecutando. El programa elimina la tarea antes de la demora de 5 segundos, eliminándola en este momento no dejará una tarea perdida en el programador.

  • Su solución no debe implicar reiniciar el entorno Sí.

Por cierto, si alguien alguna vez se preguntó por qué las aplicaciones de Windows solían ser tan inestables (antes del advenimiento de .NET y C #), esta es una de las razones. La cantidad de manejo de errores requerida (si la hubiera incluido), la administración de recursos y la verbosidad configuran situaciones muy propensas a errores si un programador es un poco flojo (el código anterior es extremadamente flojo).

Una alternativa mucho más fácil y más corta es invocar schtasks.exe. También he enviado una versión con eso en un script .BAT .

Jason C
fuente
13

BBC BASIC: un homenaje a Snow Patrol

Emulator en bbcbasic.co.uk

Este es un poco diferente. Imprime un verso de la canción "Run" y toca un arpegio de los acordes para que puedas cantar. Se inspiró en el hecho de que el comando a ejecutar (y, por lo tanto, la última línea del programa) es, por supuesto, EJECUTAR.

Todas las variables se borran al inicio del programa, por lo que toma el color de la pantalla dejado por la iteración anterior para decidir qué verso imprimir a continuación.

    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 (montaje de 4 capturas de pantalla diferentes)

ingrese la descripción de la imagen aquí

Level River St
fuente
+1 para la solución de color como alternativa de "memoria compartida".
Johannes H.
11

HTML / JavaScript:

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

El código desencadena la destrucción de la página en la que se está ejecutando, luego la recreación de otra instancia de sí mismo cuando el navegador carga la página nuevamente.

AFAIK, la única salida es matar la pestaña en la que se ejecuta la página.

EDITAR: según la solicitud popular, un código HTML5 válido:

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

fuente
@ JasonC No estoy de acuerdo. Creo que las páginas razonables deberían cumplir con las especificaciones, pero se supone que los concursos de popularidad son razonables, ¿verdad? : D entonces +1, realmente me gusta este.
yo
10

do

Este programa actúa como una gran cantidad de malware. Justo antes de que se cierre, crea un script de shell en el directorio / tmp. Se bifurca para iniciar el script de shell, lo que permite que el programa original se cierre y cancele el PID original. Después de un breve período de tiempo (2 segundos), el script de shell inicia un nuevo proceso con el programa. Por brevedad, la ubicación del programa está cableada como '/ 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]);
}

Solo hay un proceso 'interminable' ejecutándose a la vez. Cada nuevo proceso obtiene un nuevo PID. La forma más fácil de eliminar esto es eliminar el ejecutable. Si desea hacerlo más maligno, puede copiar tanto el ejecutable como el script para asegurarse de que haya varias copias en el programa en el disco en cualquier momento.

Kevin
fuente
1
Espero ver respuestas más innovadoras. Ver comentarios para preguntas sobre 'programas de suplementos'. Para mí, un programa de suplementos es solo una parte de su programa que se mantiene.
microbio
44
La bifurcación significa que tendrá dos instancias del proceso ejecutándose al mismo tiempo, incluso si están haciendo cosas diferentes.
Barry Fruitman
Sin embargo, @BarryFruitman es fácil de evitar, ya que realmente usa dos ejecutables diferentes. Es válido entonces, pero mucho menos elegante.
Johannes H.
Supongo que podría usar system()si las reglas no cuentan un fork + exec /bin/shcomo un programa complementario.
Jason C
10

Perl

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

El script emite un comando del sistema para suicidarse y canaliza el resultado en otra instancia de sí mismo. El intérprete de Perl se usa para matar, por razones multiplataforma.

Detén la locura eliminando el guión.

primo
fuente
7

Atari Basic de 8 bits

1L.:R.

Tokeniza para:

1 LIST : RUN

Internamente está limpiando las estructuras internas, esencialmente borrando el programa, antes de ejecutarlo nuevamente desde la lista.

Esto es fundamentalmente diferente de:

1L.:G.1

Que se tokeniza para:

1 LIST : GOTO 1

Este es un bucle infinito básico. Cuando los ejecutas, ves la diferencia en la velocidad (primero es más lento).


fuente
No tengo muy claro por qué la "lista" durante la ejecución del programa eliminaría cualquier estructura suprarrenal. Creo que el Atari tiene un búfer de teclado, por lo que uno podría enumerar el programa, rellenar las pulsaciones de teclas para ejecutarlo y hacer un "nuevo" con el cursor colocado para "volver a escribirlo".
supercat
@supercat - LISTA no, RUN sí.
Según esa lógica, se podría omitir la "LISTA". Por otro lado, si el programa rellena el búfer del teclado, con algunos retornos de carro, ponga "NUEVO" seguido del programa y "EJECUTAR" en los lugares correctos en la pantalla, apunte el cursor y salga, realmente se borrará a sí mismo. y se vuelve a escribir automáticamente.
supercat
@supercat: sin el LIST, no lo verías funcionando. Elegí LISTporque tiene la entrada más corta L.. Me gusta la idea de poner eso en un búfer de teclado, ¡ciertamente es lo suficientemente corto!
¿Estoy recordando correctamente que el Atari, como las máquinas Commodore, lee el texto de la pantalla cuando presionas Return? ¿Qué tan grande es el búfer del teclado? En el VIC-20 y C64, son diez bytes. Un programa que haga suficientes golpes para cargar el búfer del teclado probablemente no cabría en el búfer del teclado, pero he escrito programas que se modificarían a sí mismos al imprimir cambios en la pantalla seguidos RUN, y rellenar algunas Returnteclas. Tales cosas fueron especialmente útiles en el 64 ya que no tenía el INcomando [IIRC] que tiene Atari para fusionar líneas en un programa.
supercat
5

En un IBM Mainframe que ejecuta z / OS, ejecuta una utilidad que copia un conjunto de datos (archivo) a otro conjunto de datos (archivo). La entrada es la fuente del JCL (Job Control Language) que ha enviado para que se ejecute. La salida es el lector interno (INTRDR). También deberá asegurarse de que su sistema no permita la ejecución de múltiples nombres de trabajo idénticos. Es bueno usar una clase de trabajo que solo tiene un iniciador (lugar donde se puede ejecutar un TRABAJO en lote).

No hay PID involucrados (en z / OS), por lo que falla el conjunto de desafíos.

Detiene el proceso drenando y / o enjuagando. Si algo salió mal, drenando y / o enjuagando, jurando, pateando, intentando un arranque en caliente y finalmente con un arranque en frío o presionando el Botón Rojo Grande (y disparando al programador).

Puede que haya exagerado en el camino, pero no intentes esto en el trabajo ...

Ejemplo usando SORT. Los detalles en la tarjeta JOB dependen mucho del sitio. La política del sitio puede prohibir o impedir el uso de INTRDR. Se puede requerir una clase específica para usar el INTRDR. Si la política de su sitio prohíbe su uso , no lo use a menos que quiera llevar sus pertenencias a caminar en una caja de cartón.

Aunque hay buenos usos para el INTRDR, no lo use para este propósito . Ni siquiera tendrá la oportunidad de obtener su caja.

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

Otras utilidades están disponibles. Un programa rápido también sería fácil de hacer, solo leer un archivo, escribir un archivo.

Si desea que un ejemplo de esto salga mal, intente: http://ibmmainframes.com/viewtopic.php?p=282414#282414

La forma tradicional de copiar un conjunto de datos es usar la utilidad IBM IEBGENER, como alude ugoren en su comentario.

Sin embargo, en estos días, muchos sitios tendrán IEBGENER "alias" a ICEGENER. ICEGENER, si puede, usará DFSORT de IBM (o su rival SyncSort) para hacer una copia, porque los productos SORT están mucho más optimizados para IO que IEBGENER.

Solo estoy eliminando al intermediario usando SORT.

Si trabaja en un sitio de IBM Mainframe, conoce el formato de la tarjeta JOB que debe usar. La tarjeta de trabajo mínima es como he mostrado, sin el comentario. El comentario será importante, porque se supone que debes proporcionar información contable, por ejemplo. El nombre del trabajo probablemente tendrá un formato específico del sitio.

Algunos sitios prohíben o impiden el uso de INTRDR. Ten cuidado

Algunos sitios permiten ejecutar múltiples trabajos con el mismo nombre al mismo tiempo. Ten cuidado

Aunque a menos que sea un programador del sistema, no puede configurar una clase de este tipo, debe buscar una clase que permita solo un iniciador. Con eso, el proceso es bastante seguro, pero esté absolutamente seguro de que la clase funciona como se describe. Prueba. No con este trabajo.

Si usted es un programador del sistema, sabe que no debe hacer nada fuera de su competencia. 'Nuff dijo.

Con un trabajo con el mismo nombre permitido al mismo tiempo y un solo iniciador, esta será una secuencia constante de inicio / finalización del trabajo siguiente inicio / finalización del trabajo, hasta que complete el spool (otra cosa mala que hacer) con la salida de miles de trabajos (o quedarse sin números de trabajo). Mire una consola JES para mensajes de advertencia.

Básicamente, no hagas esto. Si lo hace, no lo haga en una máquina de producción.

Con un pequeño repaso, consideraré otra respuesta sobre cómo hacerlo en otro sistema operativo IBM Mainframe, z / VSE ... z / VSE usa JCL. z / OS usa JCL. Ellos son diferentes :-)

Bill Woodger
fuente
La idea se ve bien, pero no es una respuesta. Muéstranos el JCL - JOB, EXEC y DD - entonces será una respuesta.
ugoren
No he enviado un trabajo durante mucho tiempo, así que no estoy seguro de qué hacer con él. Si las partes que faltan son solo personalización local, entonces OK. Pero si oculta cosas para evitar un abuso, decídase: publique lo real o no publique nada. PD: solíamos IEBGENERentonces simplemente copiar.
ugoren
@ugoren Actualización adicional, incluida la explicación de por qué IEBGENER no fue seleccionado para la tarea. Al eliminar el texto del comentario en la declaración JOB, se obtiene el JCL necesario para que se ejecute, pero ser suficiente JCL depende de los estándares locales del sitio, ya sea para que el trabajo funcione o para que el programador evite ser despedido.
Bill Woodger
4

Python (72 bytes)

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

Podría hacerse más pequeño, supongo. Primero, codificando el nombre del archivo (en lugar de usar __file__). Pero aquí, puede poner este código en un archivo y ejecutarlo, sea cual sea su nombre :)

Maxime Lorant
fuente
Probablemente puedas cambiar &&a &.
Hosch250
1
¿Desde cuándo está permitido, user2509848?
Rhymoid
Bueno, podrías comenzar por eliminar el espacio en blanco ...
Ry-
66
Como no está etiquetado como code-golf , mantendré el código así :-)
Maxime Lorant
4

Programador de tareas de Windows (.BAT)

Script por lotes de Windows. Cumple con todos los requisitos de desafío.

Hasta donde puedo ver, esta es la única solución de Windows hasta ahora que cumple con todos los requisitos y no tiene dependencias no estándar (mi otra solución es similar pero requiere compilación).

@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

El programa se comporta de manera similar a mi respuesta C ++ / COM .

El programa se iniciará y registrará una tarea única con el programador de tareas de Windows para iniciarse hasta 60 segundos más tarde (Panel de control -> Herramientas administrativas -> Programador de tareas para ver, la tarea se llama "Reiniciar"). El programa hará una pausa de 5 segundos para darle la oportunidad de matarlo antes de que cree la tarea.

Utiliza la interfaz de línea de comandos del Programador de tareas schtasks.exe. La aritmética en la secuencia de comandos consiste en calcular las compensaciones de tiempo manteniendo el tiempo válido y en formato HH: MM.

Requisitos de desafío:

  • Comienza de nuevo cuando termina. Sí. La tarea se programa justo antes de la salida del programa.

  • No más de una instancia del programa ejecutándose al mismo tiempo. Sí. El programa sale completamente y no se ejecuta durante ~ 60 segundos. Lo inicia el planificador.

  • Puede ignorar cualquier instancia que el usuario inicie manualmente durante su ciclo. Sí, como efecto secundario del uso de un nombre de tarea constante.

  • Siempre y cuando esté garantizado que comience de nuevo. Sí, siempre que el Programador de tareas se esté ejecutando y schtasks.exe esté presente (ambos son verdaderos en las configuraciones predeterminadas de Windows).

  • La única forma de detener el ciclo es matar el proceso. Sí, el proceso se puede eliminar durante la ventana de 5 segundos mientras se está ejecutando. El programa elimina la tarea antes de la demora de 5 segundos, eliminándola en este momento no dejará una tarea perdida en el programador.

  • Su solución no debe implicar reiniciar el entorno Sí.

Nota: Debido a la interfaz de línea de comandos limitada, el tiempo de reinicio debe especificarse en minutos y la tarea no se reiniciará en las computadoras portátiles sin el adaptador de CA enchufado (lo siento).

Jason C
fuente
3

Unix shell

Todavía no he visto muchas soluciones que dependan de un programa no relacionado para reiniciarlo. Pero esto es exactamente para lo que at(1)se hizo la utilidad:

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

Es realmente difícil ver el programa en ejecución, ya que solo se ejecuta una vez por minuto y sale tan rápido. Afortunadamente, la atq(1)utilidad le mostrará que todavía está funcionando:

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

Y atrm(1)te permitirá romper el ciclo:

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

Puede reemplazar 1 minutecon 1 hour, o 1 week. O dele 1461 daysun programa que se ejecute una vez cada 4 años.

caja de pan
fuente
2

Potencia Shell

Estoy abusando (y posiblemente rompiendo) mi propia regla.

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

Se necesita una cantidad infinita de tiempo para reiniciarse.
Se puede matar al matar el proceso del host.

Sólo espera y mira ;)

microbiano
fuente
55
+1 para creatividad, pero -1 para hacer trampa.
Johannes H.
1
Ja, pero ¿está "garantizado que comience de nuevo" si nunca se detiene?
Jason C
Es por eso que dije que probablemente estaría rompiendo la regla. Es la belleza filosófica del infinito que puedes asumir que cualquier cosa puede pasar después de eso. La máquina de Turing también funciona de esa manera.
microbio
1
-100 porque no te apoyo para que ganes tu propio concurso, especialmente por un tecnicismo, pero +101 porque esperar a que se reinicie es la mejor excusa para postergar.
Jason C
Bueno, ya sabes, luego while true; do sleep 1; donequilifica, ¿no?
yo '
2

Golpetazo

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

Guarde esto como repeat.sh en el directorio / y dele permiso de ejecución. Se puede eliminar eliminando el archivo

Esto funciona colocando una entrada en el crontab para ejecutarla 1 minuto después.

g. cohete
fuente
2

Visual Base 6 :)

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

Para ejecutar, cree un nuevo proyecto, agregue un módulo con este código, configure el objeto de inicio en "Sub Main", compile y luego ejecute el ejecutable.


Versión más legible:

Sub Main()
    Call Shell("cmd ping 1.1.1.1 -n 1 -w 3000 > nul && """ & App.Path & "\" & App.EXEName & """")
End Sub
Cepillo de dientes
fuente
VB6 es el VB de un hombre real. ¡El último de su tipo!
Jason C
1

HTML / JAVASCRIPT

ARCHIVO HTML a.html

<script>window.location = "a.html"</script>
Clyde Lobo
fuente
1

Golpetazo

Más largo de lo que tiene que ser, pero estoy cansado y no me importa :)

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

Dijiste que tiene que reiniciarse cuando termina, no dijiste específicamente que tenía que hacerlo repetidamente o indefinidamente. Además, dijiste que nunca debería tener dos instancias ejecutándose a la vez ... nunca lo hará. ;)

Hay muchas maneras de hacer esto. Mi favorito personal sería hacer algo como enviar un paquete a algún lugar distante y luego (a través de cualquier número de métodos), hacer que la respuesta desencadene el proceso.

Ian Wizard
fuente
Técnicamente, el sleepproceso se reinicia cuando finaliza
pastebin.com slash 0mr8spkT
Si el programa es un programa que se reinicia por sí mismo , entonces está implícito que tiene que hacerlo indefinidamente; de ​​lo contrario, está reiniciando algo más que no es él mismo.
Jason C
@Jason C: Sin volverse demasiado filosófico, en la medida de lo posible, se reinicia. Podríamos debatir lo complejo que tiene que ser verdaderamente reiniciarlo uno mismo , pero creo que es mucho más allá de lo que el autor quería decir. Sin embargo, si desea que se reinicie realmente, entonces probablemente sea algo que use goto, o JMP, o cualquier construcción que su lenguaje pueda ofrecer, para volver al inicio, por lo que se está "reiniciando". De lo contrario, solo está ejecutando algo que es claramente diferente a sí mismo. Pero entonces alguien probablemente se molestará de que eso no se reinicie de verdad. Así que estoy divagando.
Ian Wizard
1

Android: una alarma reiniciará la actividad después de 1 segundo

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

}
cable67
fuente
1

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

Debe tener OpenMPI o alguna otra implementación de MPI instalada. Compilar con

mpicc -o mpifork mpifork.c

Ahora que lo pienso, no hay razón para que tengas que usar mpicc - gcc o cualquier compilador que funcione. Solo tienes que tener mpirun.

gcc -o mpifork mpifork.c

Para ejecutarlo, probablemente debería incluir el nombre completo de la ruta e incluir una lista de hosts. Por ejemplo, agregué algunas entradas en / etc / hosts que apuntaban a localhost, y lo ejecuté así:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

El ejecutable debe estar en el mismo directorio en cualquier máquina en la que desee ejecutar esto.


Básicamente, esto toma una lista de hosts proporcionados en la línea de comando, selecciona uno de los hosts y lanza el ejecutable en el host de destino con los mismos argumentos. Si todo va perfectamente, mpirun se llamará una y otra vez en diferentes máquinas (o en la misma máquina si solo proporciona 'localhost'. El ejecutable en sí (mpifork) termina, después de llamar execvp, ya no se ejecuta en la primera máquina.

Si quisieras ser malvado, puedes hacer este lanzamiento en cada máquina, incluyendo la lista completa de hosts que se proporciona en la línea de comando args. Eso volvería a generar una copia de sí mismo en cada máquina, una y otra vez: una bifurcación en racimo.

Sin embargo, de esta forma, estoy bastante seguro de que esto cumple con las reglas.

Millinon
fuente
1

JavaScript

Sin "ir a la red" cuando no es necesario :-) La programación del bucle de eventos de JavaScript nos permite escribir programas que cumplen los requisitos dados muy fácilmente:

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

Esto "reinicia" la programfunción a un ritmo de 10 veces por segundo. La naturaleza de JavaScript garantiza que solo se ejecutará una sola tarea al mismo tiempo, y no "reiniciará el entorno" como en "volver a cargar la página".

Bergi
fuente
0

Asamblea x86

No estoy completamente seguro de que esto se ajuste a sus criterios, ya que no genera un nuevo proceso, pero aquí está de todos modos.

El programa mostrará un cuadro de mensaje, asignará algo de memoria, copiará su propia sección de código en la memoria asignada y luego saltará a esa ubicación comenzando el ciclo. Debería ejecutarse hasta que malloc falle.

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'

Compilado con fasm.

Oscar
fuente
44
Como es parte de su programa llamar al código recién copiado, técnicamente su programa nunca terminó en absoluto.
microbio
66
Desde un punto de vista de bajo nivel, lo mismo podría decirse de todos los programas aquí. :-)
Brian Knoblauch
@BrianKnoblauch No estoy de acuerdo. Las respuestas más interesantes aquí parecen modificar el entorno del sistema para que una nueva copia del proceso se inicie algún tiempo después de que se elimine la primera. Por ejemplo, creo que crear un trabajo cron para ejecutar el proceso en el futuro sería una buena manera de dejar que el proceso se muera por completo y luego reiniciarlo.
Kevin - Restablece a Monica
2
@BrianKnoblauch No realmente. Un proceso es una construcción de sistema operativo (que en estos días, como desde la aparición del modo protegido en el 286 en 1982) también está respaldado por hardware a través de espacios de direcciones virtuales y memoria protegida. Cuando termina, toda esa información desaparece. Si bien no se indicó explícitamente en el desafío, considero que el espíritu del desafío significa que "reiniciar" implica que se asigna un nuevo ID de proceso.
Jason C
Bueno, le daría +1 si lograbas liberar la memoria en el camino (por favor, hazme un ping una @vez que lo hagas, ya que probablemente no lo vigile).
yo '
0

Linux upstart init

Dada la lectura más estricta de la pregunta, creo que esto es imposible. En esencia, está pidiendo un programa que comience espontáneamente con la ayuda de ningún otro programa en ejecución.

Hay algunos aty chronbasados en las respuestas, pero con la lectura más estricta, atdyanacron son los programas complementarios que están funcionando todo el tiempo, por lo que pueden ser descalificados.

Un enfoque relacionado, pero un poco más bajo es usar Linux init. Como root, agregue este archivo .conf a/etc/init/ :

descripción "forever"

comenzar en el nivel de ejecución [2345]
detenerse en el nivel de ejecución [! 2345]

reaparecer

ejecutivo dormir 10

Luego initvuelva a leer sus archivos .conf:

sudo telinit 5

Esto iniciará un sleepproceso que durará 10 segundos y luego saldrá. initluego reaparecerá sleepuna vez que detecte que el anterior se ha ido.

Por supuesto, esto todavía se está utilizando initcomo un programa complementario. Se podría argumentar que inites una extensión lógica del núcleo y siempre estará disponible en cualquier Linux.

Si esto no es aceptable, entonces supongo que el siguiente paso sería crear un módulo de kernel que reaparezca un proceso de espacio de usuario (no estoy seguro de lo fácil que es). Aquí se puede argumentar que el núcleo no es un proceso y, por lo tanto, no es un programa (complementario). Por otro lado, el núcleo es un programa en sí mismo, desde el punto de vista de la CPU.

Trauma digital
fuente
-1

TI-BASIC: 5 caracteres

llámalo prgmA

:prgmA
scrblnrd3
fuente
Puedo contar 6 caracteres. ¿Hay algo especial en contar el tamaño del programa TI-BASIC?
pastebin.com slash 0mr8spkT
Este :es solo el símbolo de inicio de línea siempre que esté programando en TI-basic. No es algo que escribes, solo está allí en el editor.
scrblnrd3
Ya veo, gracias por la información
pastebin.com slash 0mr8spkT
¿No es esa invocación recursiva? Intente incrementar Ay usar un valor de él como un caso base, verá que eventualmente saldrá.
ζ--
Bueno, todas las variables son globales en ti-basic, así que no estoy seguro. Podría ser
scrblnrd3