Um programa que termina, mas nunca termina [fechado]


35

Escreva um programa que se inicie novamente quando terminar.

Não deve haver mais de uma instância do programa em execução ao mesmo tempo. Nem mesmo por um leve momento.

Você pode ignorar qualquer instância que seja iniciada manualmente pelo usuário durante seu ciclo. Mas seu código não deve fazer isso no seu ciclo de reinicialização.

O programa pode iniciar após qualquer período de tempo, desde que seja garantido que ele será iniciado novamente.

A única maneira de parar o ciclo é matar o processo.

Sua solução não deve envolver a reinicialização do ambiente (no qual o programa está sendo executado, inclui SO, máquina, VM, shell, etc.). Somente seu programa tem permissão para reiniciar.


11
Não é isso que execacontece no linux?
Mniip

11
Estou com um pouco de preguiça de escrevê-lo agora, mas meu envio seria (para windows): "Edite o registro para que meu programa seja inicializado na inicialização. Execute shutdown -r -t 0 -f".
Cruncher

3
Matar o processo não mata o seu ciclo.
microbian

19
Acabei de perceber: se eu quiser escrever um vírus e não souber como, eu poderia 1) ir ao StackOverflow, perguntar como. Tenha ódio de todos e provavelmente a questão será encerrada. Ou 2) Vá para o código de golfe, pergunte aos outros como eles o fariam. Selecione algumas respostas criativas e a pergunta é tão popular que aparece na lista "quente" de toda a rede. Mua ha ha ha ha.
rumtscho 22/02

5
@rumtscho Sabe, essa é uma boa estratégia geral. Ok pessoal, para o meu próximo desafio, vamos ver quem pode escrever o menor firmware para o dispositivo protótipo sentado na minha mesa que atenda a todos os requisitos do documento vinculado. Para apimentar, isso deve ser feito até às 8h da manhã de segunda-feira. Vai!
Jason C

Respostas:


50

Roteiro Bash, 3 caracteres (o mais curto, possivelmente o mais elegante, embora seja reconhecidamente controverso)

$0&

Simplesmente coloca uma nova instância de si mesma em segundo plano (novo processo) e sai. A nova instância provavelmente permanecerá na fila de execução do planejador até que a instância anterior seja concluída.

Aviso - isso é difícil kill, pois o PID está mudando continuamente. Renomear temporariamente o arquivo de script é provavelmente a maneira mais simples de interromper o ciclo.

Um sistema de núcleo único é assumido. É claro que isso não é realista com o Linux no hardware bare-metal moderno, mas é facilmente configurável quando executado em uma VM. Provavelmente, poderíamos conseguir um truque semelhante usando taskset, mas isso reduziria o impacto da solução de 3 caracteres.

Esta resposta dobra as regras um pouco, pois aplica um significado específico de "execução". Haverá momentos em que o novo processo foi fork()editado e o antigo processo ainda está ativo - ou seja, pode ser possível observar mais de um PID. No entanto, o novo processo será colocado na fila de execução do planejador Linux para aguardar os ciclos da CPU, enquanto o processo existente continuará sendo executado. Neste ponto, tudo o que precisa ser feito pelo processo existente é por bashsi só exit(). Isso leva uma quantidade finita de tempo, embora eu esteja bastante confiante de que isso será feito muito antes do atual quantum de divisão do tempo / agendador. A evidência de suporte é o fato de bashiniciar e desligar em 2ms na minha VM:

$ time bash -c:

0m0.002s reais
usuário 0m0.000s
sys 0m0.000s
$ 

Evidências adicionais de apoio de que o novo processo não é realmente executado até que o processo anterior esteja concluído podem ser vistas na stracesaída:

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

Na saída, vemos que o processo original possui o PID 6929. Podemos ver a fork()chamada (na verdade clone()), que retorna um novo PID de 6930. Nesse momento, existem 2 PIDs, mas apenas 6929 estão em execução no momento:

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

straceSaída total aqui.

Podemos ver que o 6930 não emite nenhuma chamada do sistema até que o 6929 esteja completo. É razoável supor que isso significa que o 6930 não é executado até que o 6929 esteja concluído. O perfutilitário seria a melhor maneira de provar isso.


21
"reinicia ... e sai", então mais de uma instância está sendo executada ao mesmo tempo?
microbian

4
"... no núcleo único" - sim, eu também acho. Em um núcleo múltiplo, é provável que você consiga ver muitos.
blabla999

3
Se isso foi marcado como code-golf, então isso definitivamente ganhará! 1
John Odom 21/02

3
@DigitalTrauma Você está fazendo suposições enormes sobre quanto tempo leva para o bash se desligar. top não diz nada - ele é atualizado apenas uma vez a cada poucos (dezenas de) segundos, mas você está gerando muitos processos por segundo.
David Richerby

2
@ DavidRicherby - você está absolutamente certo - topnão é a ferramenta certa para usar aqui. No entanto, vejo que time bash -c :leva apenas 2ms na minha VM do Ubuntu, então não acho razoável esperar bashconcluir seu desligamento antes que seu quantum de agendamento seja feito.
Digital Trauma

26

Solução 1

PHP, 32 caracteres

Ele envia o cabeçalho e depois para. Após 3 segundos, a página é recarregada.

arquivo a.php

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

Isso pode ser interrompido encerrando a execução da página antes do envio dos cabeçalhos ou simplesmente matando o navegador.


Solução 2

PHP, 2 páginas

Vamos considerar os dois arquivos dois programas diferentes. Os dois arquivos estão na mesma pasta.

arquivo a.php

header("Location:b.php");

arquivo b.php

header("Location:a.php");

O encerramento de uma das páginas antes do envio dos cabeçalhos encerra o programa (interromper o navegador também funciona).

Aqui está o mesmo programa em

ASP.NET

arquivo a.aspx

Response.Redirect("b.aspx")

arquivo b.aspx

Response.Redirect("a.aspx")

11
Essa é uma boa solução. Espero que outros venham com respostas diferentes disso. Por isso eu o mantive como um concurso de popularidade.
microbian

Se sua resposta de recarga de 3 segundos é válida ou não, deixo para os especialistas em php. Eu acho que pode ser válido, porque é o navegador que não está esperando o seu php (eu não sou especialista).
microbian

11
Embora tecnicamente o PHP seja executado como um módulo de um servidor da Web e seu servidor não tenha sido reiniciado, acho que é válido se você considerar um arquivo .php como um script e o script for executado várias vezes.
TwiNight

Graças @TwiNight pelo feedback, eu apreciaria :)
Vereos

2
Para sua segunda solução, o navegador não detectaria um loop de redirecionamento e pararia sozinho? thedan1984.com/wp-content/uploads/2012/02/...
Ajedi32

19

sh

echo $PWD/$0 | at tomorrow

Isso funcionará em qualquer sistema compatível com Posix.

Para matá-lo, exclua o arquivo ou use atrm.


17

bater

exec "$0"

execsubstitui o shell sem criar um novo processo. Isso garante que não possa haver uma segunda instância.


11
Melhor colocá-lo ~/.bash_profile!
yegle 22/02

@ yegle: $0é -bashquando .bash_profileé originada, o que resultaria apenas em um erro de sintaxe.
Dennis

Opa, você está certo.
yegle

exec ${0##-}em ~/.bash_profileobras :-)
yegle 31/03

14

Agendador de tarefas do Windows (nativo)

C ++. Um pesadelo da programação COM. Atende a todos os requisitos de desafio.

#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 com MSVC (ou MinGW GCC se você tiver todas as dependências).

O programa iniciará e registrará uma tarefa única com o agendador de tarefas do Windows para iniciar-se 5 segundos depois (Painel de Controle -> Ferramentas Administrativas -> Agendador de Tarefas para visualizar, a tarefa é denominada "Restarter"). O programa fará uma pausa por 5 segundos para lhe dar uma chance de matá-lo antes de criar a tarefa.

Requisitos do Desafio:

  • Inicia-se novamente quando termina. Sim. A tarefa é agendada imediatamente antes da saída do programa.

  • Não há mais de uma instância do programa em execução ao mesmo tempo. Sim. O programa sai totalmente e não é executado por 5 segundos. É iniciado pelo planejador.

  • Você pode ignorar qualquer instância que seja iniciada manualmente pelo usuário durante seu ciclo. Sim, como efeito colateral do uso de um nome de tarefa constante.

  • Contanto que seja garantido que ele recomeça. Sim, desde que o Agendador de tarefas esteja em execução (ele está em uma configuração padrão do Windows).

  • A única maneira de parar o ciclo é matar o processo. Sim, o processo pode ser interrompido durante a janela de 5 segundos enquanto estiver em execução. O programa exclui a tarefa antes do atraso de 5 segundos, eliminá-la neste momento não deixará uma tarefa perdida no agendador.

  • Sua solução não deve envolver a reinicialização do ambiente Sim.

A propósito, se alguém já se perguntou por que os aplicativos Windows eram tão instáveis ​​(antes do advento do .NET e C #), esse é um dos motivos. A quantidade de manipulação de erros necessária (se eu a incluísse), o gerenciamento de recursos e a verbosidade configuram situações muito propensas a erros se um programador é mesmo um pouquinho preguiçoso (o código acima é extremamente preguiçoso).

Uma alternativa muito mais fácil e mais curta é invocar o schtasks.exe. Enviei uma versão com isso também em um script .BAT .


13

BBC BASIC - uma homenagem ao Snow Patrol

Emulador em bbcbasic.co.uk

Este é um pouco diferente. Ele imprime um verso da música "Run" e toca um arpejo dos acordes para que você possa cantar junto. Foi inspirado pelo fato de que o comando para executar (e, portanto, a última linha do programa) é, obviamente, EXECUTAR.

Todas as variáveis ​​são limpas no início do programa; portanto, a cor da tela deixada pela iteração anterior decide o versículo a ser impresso a seguir.

    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

SAÍDA (montagem de 4 capturas de tela diferentes)

insira a descrição da imagem aqui


+1 para a solução em cores como alternativa "memória compartilhada".
Johannes H.

11

HTML / JavaScript:

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

O código aciona a destruição da página em que está sendo executada e a recriação de outra instância quando o navegador carrega a página novamente.

AFAIK, a única saída é matar a guia na qual a página está sendo executada.

EDIT: conforme solicitação popular, um código HTML5 válido:

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

@JasonC Eu discordo. Penso que páginas razoáveis ​​devem estar em conformidade com as especificações, mas os concursos de popularidade devem ser razoáveis, não é? : D so +1, eu realmente gosto deste.
yo

10

C

Este programa atua como muitos malwares. Antes de fechar, ele cria um script de shell no diretório / tmp. É necessário iniciar o shell script, o que permite que o programa original feche e cancele o PID original. Após um breve período de tempo (2 segundos), o shell script inicia um novo processo com o programa. Por uma questão de brevidade, o local do programa é conectado 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]);
}

Existe apenas um processo sem fim em execução por vez. Cada novo processo recebe um novo PID. A maneira mais fácil de eliminar isso é excluir o executável. Se você quiser torná-lo mais maligno, copie o executável e o script para garantir que haja várias cópias no programa em disco a qualquer momento.


11
Espero ver respostas mais inovadoras. Veja os comentários para a pergunta sobre 'programas complementares'. Para mim, um programa de suplementos é apenas uma parte do seu programa que permanece por aí.
microbian

4
Bifurcação significa que você terá duas instâncias do processo em execução ao mesmo tempo, mesmo que estejam fazendo coisas diferentes.
Barry Fruitman

@ BarryFruitman fácil de evitar, no entanto, usando realmente dois executáveis ​​diferentes. É válido então, mas muito menos elegante.
Johannes H.

Suponho que você poderia usar system()se as regras não contarem um fork + exec /bin/shcomo um programa suplementar.
Jason C

10

Perl

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

O script emite um comando do sistema para se matar e direcionar o resultado para outra instância. O intérprete Perl é usado para matar, por razões de plataforma cruzada.

Pare a loucura excluindo o script.


7

Atari básico de 8 bits

1L.:R.

Tokeniza para:

1 LIST : RUN

Internamente, ele limpa as estruturas internas, basicamente eliminando o programa, antes de executá-lo novamente a partir da listagem.

Isso é fundamentalmente diferente de:

1L.:G.1

Que tokeniza para:

1 LIST : GOTO 1

Este é um loop infinito básico. Ao executá-las, você vê a diferença de velocidade (a primeira é mais lenta).


Não estou muito claro por que a "lista" durante a execução do programa eliminaria quaisquer estruturas interenais. Eu acho que o Atari tem um buffer de teclado, então é possível listar o programa, digitar as teclas para executá-lo e fazer um "novo" com o cursor posicionado para "redigitá-lo".
Supercat 22/02

@supercat - LIST não, RUN sim.

Por essa lógica, pode-se omitir a "LIST". Por outro lado, se o programa encheu o buffer do teclado, com alguns retornos de carro, coloque "NEW" seguido do programa e "RUN" nos pontos certos da tela, localize o cursor e saia, ele se apagará genuinamente e redigite-se automaticamente.
supercat 23/02

@ supercat - sem o LIST, você não o veria correndo. Eu escolhi LISTporque tem a menor entrada L.. Eu gosto da idéia de colocar isso em um buffer de teclado, é certamente curto o suficiente!

Estou lembrando corretamente que o Atari, como as máquinas Commodore, lê o texto da tela quando você pressiona Return? Qual é o tamanho do buffer do teclado? No VIC-20 e C64, são dez bytes. Um programa que faz toques suficientes para carregar o buffer do teclado provavelmente não se encaixaria no buffer do teclado, mas escrevi programas que se modificariam imprimindo alterações na tela seguidas RUNe Returnpressionando algumas teclas. Tais coisas foram especialmente úteis nos 64, pois não possuíam o INcomando [IIRC] que o Atari possui para mesclar linhas em um programa.
Supercat 24/02

5

Em um IBM Mainframe executando o z / OS, você executa um utilitário que copia um conjunto de dados (arquivo) para outro conjunto de dados (arquivo). A entrada é a fonte da JCL (Job Control Language) que você enviou para fazer com que ela seja executada. A saída é o leitor interno (INTRDR). Você também precisará garantir que seu sistema não permita a execução de vários nomes de tarefas idênticos. É bom usar uma classe de trabalho que possui apenas um iniciador (local onde um JOB pode ser executado em lote).

Não há PIDs envolvidos (no z / OS), portanto falha no conjunto de desafios.

Você interrompe o processo drenando e / ou lavando. Se algo der errado, drenando e / ou lavando, xingando, chutando, tentando um arranque a quente e, finalmente, iniciando a frio ou pressionando o Grande Botão Vermelho (e disparando no programador).

Eu posso ter exagerado ao longo do caminho, mas não tente fazer isso no trabalho ...

Exemplo usando SORT. Os detalhes no cartão JOB são muito dependentes do site. A política do site pode proibir ou impedir o uso do INTRDR. Uma classe específica pode ser necessária para usar o INTRDR. Se a política do site proibir seu uso , não a use, a menos que você queira levar seus pertences para passear em uma caixa de papelão.

Embora haja bons usos para o INTRDR, não o utilize para esse fim . Você nem terá a chance de pegar sua caixa.

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

Outros utilitários estão disponíveis. Um programa rápido também seria fácil, basta ler um arquivo, escrever um arquivo.

Se você quiser que um exemplo disso dê errado, tente: http://ibmmainframes.com/viewtopic.php?p=282414#282414

A maneira tradicional de copiar um conjunto de dados é usar o utilitário IBM IEBGENER, como a ugoren faz alusão em seus comentários.

No entanto, atualmente, muitos sites têm o IEBGENER "alias" para o ICEGENER. O ICEGENER, se puder, usará o DFSORT da IBM (ou seu rival SyncSort) para fazer uma cópia, porque os produtos SORT são muito mais otimizados para IO do que o IEBGENER.

Estou apenas cortando o intermediário usando SORT.

Se você trabalha em um site IBM Mainframe, conhece o formato da placa JOB que deve usar. O cartão mínimo de trabalho é como eu mostrei, sem o comentário. O comentário será importante, porque você pode estar fornecendo informações contábeis, por exemplo. O nome do trabalho provavelmente terá um formato específico do site.

Alguns sites proíbem ou impedem o uso do INTRDR. Estar ciente.

Alguns sites permitem que vários trabalhos com o mesmo nome sejam executados ao mesmo tempo. Estar ciente.

Embora, a menos que você seja um programador do sistema, não possa configurar essa classe, procure uma classe que permita apenas um iniciador. Com isso, o processo é bastante seguro - mas tenha certeza absoluta de que a classe está funcionando como descrito. Teste. Não com este trabalho.

Se você é um programador do sistema, sabe que não deve fazer nada fora do seu mandato. disse nuff.

Com um trabalho com o mesmo nome permitido ao mesmo tempo e um único iniciador, este será um fluxo constante de início / término do trabalho próximo / início / término do trabalho - até você preencher o spool (outra coisa ruim a fazer) com a saída de milhares de trabalhos (ou os números acabam). Assista a um console JES para obter mensagens de aviso.

Basicamente, não faça isso. Se você fizer isso, não faça em uma máquina de produção.

Com um pouco de detalhamento, considerarei outra resposta sobre como fazê-lo em outro sistema operacional IBM Mainframe, z / VSE ... z / VSE usa JCL. O z / OS usa JCL. Eles são diferentes :-)


A ideia parece boa, mas não é uma resposta. Mostre-nos o JCL - JOB, EXEC e DD - então será uma resposta.
precisa saber é o seguinte

Não enviei um trabalho por muito tempo, por isso não sei o que fazer dele. Se as peças ausentes forem apenas personalização local, OK. Mas se você esconder coisas para impedir um abuso, decida-se - publique a coisa real ou não publique nada. PS: Na IEBGENERépoca, costumávamos simplesmente copiar.
21414 ugoren

@ugoren Atualização adicional, incluindo explicação de por que o IEBGENER não foi selecionado para a tarefa. A remoção do texto do comentário na instrução JOB fornece a JCL necessária para sua execução, mas a JCL suficiente depende dos padrões do site local, para o trabalho funcionar ou para o programador evitar ser demitido.
Bill Woodger

4

Python (72 bytes)

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

Poderia ser menor, eu acho. Primeiro, codificando o nome do arquivo (em vez de usá-lo __file__). Mas aqui, você pode colocar esse código em um arquivo e executá-lo, seja qual for o nome :)


Você provavelmente pode mudar &&para &.
Hosch250

11
Desde quando isso é permitido, user2509848?
Rhymoid

Bem, você poderia começar removendo o espaço em branco ...
Ry- 22-22

6
Uma vez que não é marcado código-golf , vou manter o código como este :-)
Maxime Lorant

4

Agendador de tarefas do Windows (.BAT)

Script em lote do Windows. Atende a todos os requisitos de desafio.

Até onde posso ver, esta é a única solução do Windows até agora que atende a todos os requisitos e não possui dependências fora do padrão (minha outra solução é semelhante, mas requer compilação).

@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

O programa se comporta de maneira semelhante à minha resposta C ++ / COM .

O programa iniciará e registrará uma tarefa única no agendador de tarefas do Windows para iniciar-se até 60 segundos depois (Painel de Controle -> Ferramentas Administrativas -> Agendador de Tarefas para visualizar, a tarefa é denominada "Restarter"). O programa fará uma pausa por 5 segundos para lhe dar uma chance de matá-lo antes de criar a tarefa.

Faz uso da interface do Agendador de tarefas da linha de comando schtasks.exe. A aritmética no script é calcular as compensações de tempo, mantendo o tempo válido e no formato HH: MM.

Requisitos do Desafio:

  • Inicia-se novamente quando termina. Sim. A tarefa é agendada imediatamente antes da saída do programa.

  • Não há mais de uma instância do programa em execução ao mesmo tempo. Sim. O programa sai completamente e não é executado por ~ 60 segundos. É iniciado pelo planejador.

  • Você pode ignorar qualquer instância que seja iniciada manualmente pelo usuário durante seu ciclo. Sim, como efeito colateral do uso de um nome de tarefa constante.

  • Contanto que seja garantido que ele recomeça. Sim, desde que o Agendador de tarefas esteja em execução e o schtasks.exe esteja presente (ambos verdadeiros nas configurações padrão do Windows).

  • A única maneira de parar o ciclo é matar o processo. Sim, o processo pode ser interrompido durante a janela de 5 segundos enquanto estiver em execução. O programa exclui a tarefa antes do atraso de 5 segundos, eliminá-la neste momento não deixará uma tarefa perdida no agendador.

  • Sua solução não deve envolver a reinicialização do ambiente Sim.

Nota: Devido à interface limitada da linha de comandos, o tempo de reinicialização deve ser especificado em minutos e a tarefa não será reiniciada nos laptops sem o adaptador CA conectado (desculpe).


3

Shell Unix

Ainda não vi muitas soluções que dependem de um programa não relacionado para reiniciá-lo. Mas é exatamente para isso que o at(1)utilitário foi criado:

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

É difícil realmente pegar o programa em execução, pois ele é executado apenas uma vez por minuto e sai tão rapidamente. Felizmente, o atq(1)utilitário mostra que ainda 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

E atrm(1)permitirá que você quebre o ciclo:

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

Você pode substituir 1 minutepor 1 hour, ou 1 week. Ou dê 1461 daysum programa que seja executado uma vez a cada 4 anos.


2

PowerShell

Estou abusando (e possivelmente violando) minha própria regra.

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

Leva uma quantidade infinita de tempo para se reiniciar.
Pode ser eliminado matando o processo host.

Apenas espere e veja;)


5
+1 para criatividade, mas -1 para trapaça.
Johannes H.

11
Ha, mas é "garantido que recomeça" se nunca parar?
Jason C

Por isso eu disse que provavelmente estaria infringindo a regra. É a beleza filosófica do infinito que você pode assumir que tudo pode acontecer depois disso. A máquina de Turing também funciona dessa maneira.
microbian

11
-100 porque eu não apoio você a ganhar seu próprio concurso, especialmente em termos técnicos, mas +101 porque esperar pelo reinício é a melhor desculpa de procrastinação de todos os tempos.
Jason C

Bem, você sabe, então while true; do sleep 1; donequilifica, não é?
yo

2

Bater

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

Salve isso como repeat.sh no diretório / e conceda permissão de execução. Pode ser eliminado excluindo o arquivo

Isso funciona colocando uma entrada no crontab para executá-lo 1 minuto depois.


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 executar, crie um novo projeto, adicione um módulo com esse código, defina o objeto de inicialização como "Sub Main", compile e execute o executável.


Versão mais legível:

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

O VB6 é o VB de um homem real. O último de seu tipo!
Jason C

1

HTML / JAVASCRIPT

ARQUIVO HTML a.html

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

1

Bater

Mais tempo do que deve ser, mas estou cansado e não me importo :)

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

Você disse que ele precisa se reiniciar quando terminar, não disse especificamente que tinha que fazê-lo repetidamente ou indefinidamente. Além disso, você disse que nunca deve haver duas instâncias em execução ao mesmo tempo ... isso nunca acontecerá. ;)

Existem várias maneiras de fazer isso. Meu favorito pessoal, seria fazer algo como enviar um pacote para algum lugar distante e, em seguida (através de vários métodos), fazer com que a resposta iniciasse o processo.


Tecnicamente, o sleepprocesso reinicia quando termina
pastebin.com slash 0mr8spkT

Se o programa é um programa que reinicia-lo auto , em seguida, fica implícito que ele tem de fazê-lo indefinidamente - caso contrário ele está reiniciando outra coisa que não seja em si.
Jason C

@ Jason C: Sem ficar muito filosófico, na medida do possível, ele se reinicia. Poderíamos debater o quão complexo ele tem que ser verdadeiramente reinicie-o auto , mas eu acho que é muito além do que o autor quis dizer. No entanto, se você deseja que ele realmente se reinicie, provavelmente seria algo que usa goto, ou JMP, ou qualquer outra construção que seu idioma possa oferecer, para voltar ao início, então está "reiniciando". Caso contrário, está apenas executando algo que é distintamente semelhante a si mesmo. Mas então alguém provavelmente terá o problema de que isso não está realmente reiniciando. Então eu discordo.
Ian Wizard

1

Android: um alarme reiniciará a atividade após 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();
}

}

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

Você deve ter o OpenMPI ou alguma outra implementação MPI instalada. Ajuntar com

mpicc -o mpifork mpifork.c

Agora que penso nisso, não há razão para você usar o mpicc - gcc ou qualquer outro compilador que funcione. Você só precisa ter mpirun.

gcc -o mpifork mpifork.c

Para executá-lo, você provavelmente deve incluir o nome completo do caminho e uma lista de hosts. Por exemplo, adicionei algumas entradas no / etc / hosts que apontavam para o localhost e executei-o assim:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

O executável deve estar no mesmo diretório em qualquer máquina em que você deseja executá-lo.


Essencialmente, isso pega uma lista de hosts fornecidos na linha de comando, seleciona um dos hosts e inicia o executável no host de destino com os mesmos argumentos. Se tudo correr perfeitamente, o mpirun se chamará repetidamente em máquinas diferentes (ou a mesma máquina se você fornecer apenas 'localhost'. O próprio executável (mpifork) termina - após chamarexecvp , ele não está mais sendo executado na primeira máquina.

Se você quisesse ser mau, poderia fazer esse lançamento em todas as máquinas, incluindo a lista completa de hosts fornecidos na linha de comando emargs . Isso geraria uma cópia de si mesma em todas as máquinas, repetidas vezes - um forkbomb de cluster.

No entanto, nesta forma, tenho certeza de que isso satisfaz as regras.


1

Javascript

Sem "ir para a rede" quando não é necessário :-) O agendamento do loop de eventos do JavaScript nos permite escrever programas que atendem aos requisitos fornecidos com muita facilidade:

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

Isso "reinicia" a programfunção em um ritmo de 10 vezes por segundo. É garantido pela natureza do JavaScript que apenas uma única tarefa será executada ao mesmo tempo e não "reinicia o ambiente", como em "recarregar a página".


0

Montagem x86

Não tenho certeza absoluta de que isso se encaixa nos seus critérios, pois não gera um novo processo, mas aqui está mesmo assim.

O programa mostrará uma caixa de mensagem, alocará um pouco de memória, copiará sua própria seção de código na memória alocada e, em seguida, pulará para esse local iniciando o ciclo. Deve ser executado até o malloc falhar.

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 com fasm.


4
Como faz parte do seu programa chamar o código recém-copiado, então tecnicamente o seu programa nunca termina.
microbian

6
Do ponto de vista de baixo nível, o mesmo poderia ser dito de todos os programas aqui. :-)
Brian Knoblauch

@BrianKnoblauch Eu discordo. As respostas mais interessantes aqui parecem modificar o ambiente do sistema para que uma nova cópia do processo seja iniciada algum tempo após a morte da primeira. Por exemplo, eu pensaria que criar um trabalho chron para executar o processo no futuro seria uma boa maneira de deixar o processo morrer completamente e depois ser reiniciado.
Kevin - Restabelece Monica

2
@BrianKnoblauch Na verdade não. Um processo é uma construção de sistema operacional (que hoje em dia - como desde o advento do modo protegido no 286 em 1982 - também é suportada por hardware através de espaços de endereço virtuais e memória protegida). Quando termina, todas essas informações desaparecem. Embora não tenha sido explicitamente declarado no desafio, considero que o espírito do desafio significa que "reiniciar" implica que um novo ID do processo seja atribuído.
Jason C

Bem, eu daria +1 se você conseguisse liberar a memória no caminho (por favor, faça ping em mim @ assim que conseguir, pois provavelmente não vou ficar de olho nela).
yo

0

Linux iniciante iniciante

Dada a leitura mais estrita da questão, acho que isso é impossível. Em essência, ele está solicitando que um programa inicie espontaneamente com a ajuda de outros programas em execução.

Existem alguns atechron baseados em respostas, mas com a leitura mais rigorosa, atdeanacron são programas complementares que estão funcionando o tempo todo, para que eles possam ser desqualificado.

Uma abordagem relacionada, mas um nível um pouco mais baixo é usar o Linux init. Como root, adicione este arquivo .conf ao/etc/init/ :

descrição "forever"

iniciar no nível de execução [2345]
parar no nível de execução [! 2345]

reaparecimento

exec sono 10

Então tem init leia novamente seus arquivos .conf:

sudo telinit 5

Isso iniciará um sleep processo que permanecerá por 10 segundos e depois sairá. initreaparecerá sleepassim que detectar que o anterior desapareceu.

Claro que isso ainda está sendo usado initcomo um programa suplementar. Você pode argumentar que inité uma extensão lógica do kernel e irá sempre estará disponível em qualquer Linux.

Se isso não for aceitável, acho que a próxima coisa a ser feita em nível inferior seria criar um módulo do kernel que reaparece no processo do espaço do usuário (não sei o quão fácil isso é). Aqui pode-se argumentar que o kernel não é um processo e, portanto, não é um programa (suplementar). Por outro lado, o kernel é um programa por si só, do ponto da CPU.


-1

TI-BASIC: 5 caracteres

chame-o prgmA

:prgmA

Eu posso contar 6 caracteres. Existe algo de especial na contagem do tamanho do programa TI-BASIC?
pastebin.com barra 0mr8spkT

O :símbolo é apenas o início da linha sempre que você estiver programando no TI-basic. Não é algo que você digita, está apenas no editor.
scrblnrd3

Entendo, obrigado pela informação
pastebin.com slash 0mr8spkT

Isso não é invocação recursiva? Tente incrementar Ae usar um valor dele como um caso base.
ζ--

Bem, todas as variáveis ​​são globais em ti-basic, então não tenho certeza. Pode ser #
scrblnrd3
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.