程序结束但永不结束[关闭]


35

编写一个程序,完成后再次启动。

同时运行的程序实例不应超过一个。甚至没有丝毫时间。

您可以忽略周期中用户手动启动的任何实例。但是您的代码不应在重新启动周期中执行此操作。

程序可以在任何时间后启动,只要可以保证再次启动即可。

停止周期的唯一方法是终止进程。

您的解决方案不应该涉及重新启动环境(运行程序的环境,包括操作系统,计算机,VM,shell等)。只允许您的程序重新启动。


11
这不就是execlinux中的功能吗?
mniip 2014年

11
我现在有点懒惰,但是我的提交是(对于Windows):“编辑注册表,以便程序在启动时启动。运行shutdown -r -t 0 -f”。
Cruncher

3
终止进程不会杀死循环。
microbian

19
我刚刚意识到:如果我想编写病毒但不知道怎么做,我可以1)进入StackOverflow,请问如何做。得到所有人的仇恨,这个问题可能会结束。或2)去打高尔夫,问别人他们会怎么做。您可以从中找到一些创造性的答案,这个问题非常受欢迎,因此它出现在网络范围的“热门”列表中。啊哈哈哈哈
rumtscho 2014年

5
@rumtscho您知道,这是一个很好的一般策略。好的,对于我的下一个挑战,让我们看看谁能为坐在我办公桌上的原型设备编写最小的固件,从而满足链接文档中的所有要求。为了增加趣味性,必须在星期一早上8AM之前完成。走!
杰森C

Answers:


50

Bash脚本,3个字符(最短,可能是最优雅的,尽管有争议)

$0&

只需将自己的新实例放在后台(新过程),然后退出即可。新实例可能会保留在调度程序运行队列中,直到完成前一个实例为止。

警告-这很难kill,因为PID不断变化。临时重命名脚本文件可能是打破周期的最简单方法。

假设使用单核系统。当然,对于现代裸机硬件上的Linux,这是不现实的,但是在VM中运行时很容易配置。使用可能可以实现类似的技巧taskset,但这将减少3-char解决方案的影响。

这个答案在应用“运行”的特定含义时稍微改变了规则。有时会执行新过程fork(),而旧过程仍然存在-即可能有可能观察到多个PID。但是,新进程将放置在Linux调度程序运行队列中,以等待CPU周期,而现有进程将继续执行。在这一点上,现有流程需要做的全部工作就是bash自己exit()。这确实需要花费有限的时间,尽管我相当有信心,它将在当前的时间片/调度程序量子完成之前完成。支持的事实是bash我的虚拟机在2毫秒内启动和关闭的事实:

$ time bash -c:

真实0m0.002s
用户0m0.000s
sys 0m0.000s
$ 

strace输出中可以看到进一步的支持证据,表明新流程直到之前的流程完成才真正运行。

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

在输出中,我们看到原始进程的PID为6929。我们可以看到fork()调用(实际上是clone()),该调用返回一个新的PID为6930。这时有2个PID,但当前仅运行6929:

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

全部strace输出在这里。

我们可以看到6930在6929完成之前不会发出任何系统调用。可以合理地假设,这意味着6930直到6929完成才完全运行。该perf实用程序将是证明这一点的最终方法。


21
“重新启动...,然后退出”,那么同时运行多个实例吗?
microbian

4
“ ...在单核上”-是的,我也会这么想。在多核上,您可能会看到很多。
blabla999

3
如果这被标记为代码高尔夫,那么这肯定会赢!+1
约翰·奥多姆

3
@DigitalTrauma您正在对bash关闭自身所需的时间进行大量假设。top不会告诉您任何内容,它只会每隔几十秒更新一次,但每秒会产生许多进程。
David Richerby 2014年

2
@DavidRicherby(您绝对正确top)不是在此处使用的正确工具。但是我看到time bash -c :在我的Ubuntu VM上仅花费2毫秒,因此我认为bash在完成调度时间之前不要期望完成其关闭是不合理的。
Digital Trauma

26

解决方案1

PHP,32个字符

它发送头,然后停止。3秒后,页面将重新加载。

文件a.php

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

可以通过在发送标头之前终止页面的执行,或仅通过终止浏览器来停止此操作。


解决方案2

PHP,2页

让我们考虑两个文件这两个不同的程序。这两个文件位于同一文件夹中。

文件a.php

header("Location:b.php");

文件b.php

header("Location:a.php");

在发送标头之前终止其中一个页面会终止程序(也将终止浏览器的工作)。

这是相同的程序

ASP.NET

文件a.aspx

Response.Redirect("b.aspx")

文件b.aspx

Response.Redirect("a.aspx")

1
那是一个很好的解决方案。我希望其他人给出的答案与此不同。这就是为什么我将其保留为人气竞赛的原因。
microbian

无论您的3秒重新加载答案是否有效,我都将其留给php专家。我认为这可能是有效的,因为正在等待浏览器的不是您的php(我不是专家)。
microbian

1
虽然从技术上讲PHP是作为Web服务器的模块运行的,并且Web服务器没有重新启动,但我认为将.php文件作为脚本并且该脚本多次运行是有效的。
TwiNight 2014年

@TwiNight感谢您的反馈,我非常感激:)
Vereos 2014年

2
对于第二种解决方案,浏览器是否不会检测到重定向循环并自行停止?thedan1984.com/wp-content/uploads/2012/02/...
Ajedi32

19

SH

echo $PWD/$0 | at tomorrow

这将在任何符合Posix的系统上工作。

要杀死它,请删除文件或使用atrm


17

重击

exec "$0"

exec替换外壳而不创建新进程。这样可以确保没有第二个实例。


1
最好放进去~/.bash_profile
yegle 2014年

@yegle:$0-bashwhen .bash_profile的来源,因此只会导致语法错误。
丹尼斯

糟糕,您是对的。
yegle 2014年

exec ${0##-}~/.bash_profile工作中:-)
yegle 2014年

14

Windows Task Scheduler(本机)

C ++。COM编程的噩梦。满足所有挑战要求。

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

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

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


int main () {

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

    const char *name = "Restarter";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}


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

    SYSTEMTIME when;
    FILETIME whenf;
    LARGE_INTEGER tempval;

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

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

}

使用MSVC(或MinGW GCC,如果您具有所有依赖项)进行编译。

程序将启动并在Windows任务计划程序中注册一个一次性任务,以在5秒后启动自身(控制面板->管理工具->任务计划程序以查看,任务名为“ Restarter”)。程序将暂停5秒钟,以便您有机会在创建任务之前将其杀死。

挑战要求:

  • 完成后再次启动自身。 是。任务排定在程序退出之前。

  • 同一时间运行的程序不得超过一个实例。 是。程序完全退出,并且没有运行5秒钟。它由调度程序启动。

  • 您可以忽略周期中用户手动启动的任何实例。 是的,作为使用恒定任务名称的副作用。

  • 只要保证它再次启动即可。 是的,前提是Task Scheduler正在运行(它是标准Windows配置)。

  • 停止周期的唯一方法是终止进程。 是的,该进程可以在运行的5秒钟窗口中终止。程序会在5秒延迟之前删除任务,此时将其杀死不会在计划程序中留下杂散任务。

  • 您的解决方案不应涉及重新启动环境 。是。

顺便说一句,如果有人想知道为什么Windows应用程序曾经如此不稳定(在.NET和C#出现之前),这就是原因之一。如果程序员甚至一点点懒惰(上面的代码都是非常懒惰的),那么所需的错误处理量(包括我在内),资源管理和冗长性都会造成非常容易出错的情况。

一个更简单,更简短的选择是调用schtasks.exe。我也已经在.BAT脚本中提交了带有该版本的版本


13

BBC BASIC-向Snow Patrol致敬

bbcbasic.co.uk上的仿真器

这有点不同。它会打印歌曲“ Run”的一首诗,并播放和弦的琶音,以便您可以唱歌。它受到以下事实的启发:要执行的命令(以及程序的最后一行)当然是RUN。

所有变量都在程序开始时清除,因此需要使用上一次迭代留下的屏幕颜色来决定接下来要打印的经文。

    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

输出(4个不同屏幕截图的剪辑)

在此处输入图片说明


+1用于颜色解决方案,作为“共享内存”的替代方案。
Johannes H.

11

HTML / JavaScript:

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

该代码将触发正在运行的页面的破坏,然后在浏览器重新加载页面时重新创建其自身的另一个实例。

AFAIK,唯一的出路就是取消正在页面运行的标签页。

编辑:根据普遍要求,有效的HTML5代码:

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

@JasonC我不同意。我认为合理的页面应符合规范,但是颇受欢迎的竞赛应该是合理的,对吗?:D所以+1,我真的很喜欢这个。
2014年

10

C

该程序就像很多恶意软件一样。在关闭之前,它会在/ tmp目录中创建一个shell脚本。它分叉启动shell脚本,该脚本允许原始程序关闭并取消原始PID。短时间(2秒)后,shell脚本将使用该程序启动新进程。为简便起见,程序位置硬接线为“ / 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]);
}

一次只运行一个“ everever”进程。每个新进程都会获得一个新的PID。最简单的方法是删除可执行文件。如果要使其更具恶性,可以同时复制可执行文件和脚本,以确保磁盘上的程序随时都有多个副本。


1
我希望看到更多创新的答案。有关“补充计划”的问题,请参阅评论。对我来说,补充程序只是您所徘徊的程序的一部分。
microbian

4
分叉意味着您将同时运行流程的两个实例,即使它们在做不同的事情。
Barry Fruitman 2014年

但是,通过真正使用两个不同的可执行文件,可以轻松避免@BarryFruitman。那时是有效的,但是不太优雅。
Johannes H.

我想system()如果规则不将fork + exec /bin/sh视为补充程序,则可以使用。
杰森C

10

佩尔

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

该脚本发出系统命令来杀死自己,并将结果通过管道传递到其自身的另一个实例中。由于跨平台的原因,Perl解释器用于执行杀死操作。

通过删除脚本来停止疯狂。


7

Atari 8位基本版

1L.:R.

标记为:

1 LIST : RUN

在内部,它清除内部结构,从本质上清除程序,然后从清单中再次运行它。

这从根本上不同于:

1L.:G.1

标记为:

1 LIST : GOTO 1

这是一个基本的无限循环。运行它们时,您会看到速度的差异(首先是速度较慢)。


我不太清楚为什么程序执行过程中的“列表”会清除任何内部结构。我认为Atari有一个键盘缓冲区,因此可以列出该程序,填充要运行的击键,并使用定位为“重新键入”的光标进行“新”操作。
2014年

@supercat-LIST没有,RUN有。

按照这种逻辑,可以省略“ LIST”。另一方面,如果程序填充了键盘缓冲区,并返回了一些回车符,则在屏幕上的正确位置放“ NEW”,然后放程序,然后将“ RUN”放到屏幕上的正确位置,将光标放到原处,然后退出,它将真正擦除自身并自动重新输入。
supercat 2014年

@supercat-如果没有LIST,您将看不到它的运行。我之所以选择,LIST是因为它的输入时间最短L.。我喜欢将其放入键盘缓冲区的想法,它肯定足够短!

我是否正确记得Atari像Commodore机一样,在您按下时会从屏幕上读取文本Return?键盘缓冲区有多大?在VIC-20和C64上,它是10个字节。一个执行足够戳操作以加载键盘缓冲区的程序可能无法容纳在键盘缓冲区中,但是我编写了一些程序,该程序可以通过将更改打印到屏幕上来进行修改RUN,然后Return按键,并填充一些击键。这些东西在64位上特别有用,因为它没有INAtari用来将行合并到程序中的[IIRC] 命令。
supercat 2014年

5

在运行z / OS的IBM Mainframe上,运行一个实用程序,该实用程序将一个数据集(文件)复制到另一个数据集(文件)。输入是已提交以使其运行的JCL(作业控制语言)的源。输出是内部读取器(INTRDR)。您还需要确保您的系统不允许运行多个相同的作业名。使用仅具有一个启动器(作业可以在其中批量运行的地方)的作业类很好。

(在z / OS中)不涉及PID,因此挑战集失败。

您通过排干和/或冲洗来中止过程。如果出了问题,则要排干和/或冲洗,发誓,踢人,尝试热启动,最后通过冷启动或按“大红色按钮”(并射击程序员)。

一路上我可能有些夸张,但不要在工作中尝试此方法...

使用SORT的示例。JOB卡上的详细信息取决于站点。网站政策可能会禁止或禁止使用INTRDR。使用INTRDR可能需要特定的类。如果您的网站政策禁止其使用,则除非您想将自己的物品带到纸板箱中散步,否则请不要使用它

尽管INTRDR有很好的用途,但请勿将其用于此目的。您甚至没有机会拿到盒子。

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

其他实用程序也可用。快速程序也很容易做到,只需读取文件,写入文件即可。

如果您想要此错误示例,请尝试:http : //ibmmainframes.com/viewtopic.php?p=282414#282414

ugoren在其评论中暗示,复制数据集的传统方法是使用IBM实用程序IEBGENER。

但是,这些天来,许多站点都将IEBGENER别名为ICEGENER。如果可能的话,ICEGENER将使用IBM的DFSORT(或其竞争对手SyncSort)进行复制,因为SORT产品比IEBGENER在IO方面的优化程度更高。

我只是通过使用SORT剔除中间人。

如果您在IBM Mainframe站点工作,则知道应该使用的JOB卡的格式。最小的JOB卡是我所显示的,没有评论。注释将很重要,因为例如您可能应该提供会计信息。作业名称可能具有特定于站点的格式。

一些站点禁止或禁止使用INTRDR。意识到。

一些站点允许多个具有相同名称的作业同时运行。意识到。

尽管除非您是系统程序员,否则您无法设置这样的类,但是您应该寻找仅允许一个启动器的类。这样,该过程是相当安全的-但要绝对确定该类是否按所述方式工作。测试。没有这份工作。

如果您是系统程序员,那么您除了在职权范围内不会做任何事情。纳夫说。

如果一个作业同时具有相同的名称,并且有一个启动程序,则这将是恒定的作业启动/完成流,下一个作业启动/完成-直到您用以下命令的输出填充假脱机(另一个不好的事情)数千个工作(或工作编号用完)。观看JES控制台以获取警告消息。

基本上,不要这样做。如果要这样做,请不要在生产机器上进行。

稍加整理,我将考虑另一个答案,以了解如何在另一个IBM Mainframe操作系统z / VSE上执行此操作。z / VSE使用JCL。z / OS使用JCL。它们不一样 :-)


这个主意看起来不错,但这不是答案。向我们展示JCL-JOB,EXEC和DD-然后它将是一个答案。
ugoren 2014年

很久没提交工作了,所以我不确定该怎么做。如果缺少的部分只是本地定制,则单击确定。但是,如果您隐藏东西以防止滥用,请下定决心-发布真实内容,或不发布任何内容。PS IEBGENER那时我们只是简单地复制。
ugoren 2014年

@ugoren进一步更新,包括为何未为任务选择IEBGENER的说明。除去JOB语句上的注释文本将为其提供运行所需的JCL,但足够的JCL取决于本地站点标准,以使工作正常进行或避免程序员被解雇。
比尔·伍德格

4

Python(72字节)

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

我猜可能会变小。首先,通过对文件名进行硬编码(而不是使用__file__)。但是在这里,无论其名称是什么,您都可以将此代码放在文件中并运行它:)


您可能可以更改&&&
Hosch250

1
从什么时候开始允许,user2509848?
Rhymoid 2014年

好吧,您可以从删除空白开始……
Ry-2014年

6
因为它没有被标记为代码高尔夫,所以我将保留这样的代码:-)
Maxime Lorant

4

Windows Task Scheduler(.BAT)

Windows批处理脚本。满足所有挑战要求。

据我所知,这是迄今为止唯一满足所有要求并且没有非标准依赖性的Windows解决方案(我的其他解决方案是类似的,但需要编译)。

@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

程序的行为类似于我的C ++ / COM回答

程序将启动并在Windows任务计划程序中注册一次任务,以在60秒后启动自身(控制面板->管理工具->任务计划程序以查看,任务名为“ Restarter”)。程序将暂停5秒钟,以便您有机会在创建任务之前将其杀死。

利用命令行Task Scheduler界面schtasks.exe。脚本中的算法是在保持时间有效的同时以HH:MM格式计算时间偏移。

挑战要求:

  • 完成后再次启动自身。 是。任务排定在程序退出之前。

  • 同一时间运行的程序不得超过一个实例。 是。程序完全退出,并且无法运行约60秒。它由调度程序启动。

  • 您可以忽略周期中用户手动启动的任何实例。 是的,作为使用恒定任务名称的副作用。

  • 只要保证它再次启动即可。 是的,只要Task Scheduler正在运行并且schtasks.exe存在(在默认Windows配置中均为true)。

  • 停止周期的唯一方法是终止进程。 是的,该进程可以在运行的5秒钟窗口中终止。程序会在5秒延迟之前删除任务,此时将其杀死不会在计划程序中留下杂散任务。

  • 您的解决方案不应涉及重新启动环境 。是。

注意:由于命令行界面受限制,必须以分钟为单位指定重新启动时间,并且在未插入AC适配器的情况下,笔记本电脑上的任务将无法重新启动(对不起)。


3

Unix外壳

我还没有看到许多依靠不相关程序重新启动它的解决方案。但这正是该at(1)实用程序的用途:

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

实际上很难捕获正在运行的程序,因为它每分钟仅运行一次,并且退出速度如此之快。幸运的是,该atq(1)实用程序将向您显示它仍在继续:

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

并且atrm(1)可以让您打破循环:

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

您可以1 minute1 hour或替换1 week。或者让它1461 days拥有一个每4年运行一次的程序。


2

电源外壳

我正在滥用(并可能违反)自己的规则。

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

重新启动本身需要无限的时间。
可以通过杀死宿主进程来杀死它。

只是等着看;)


5
+1代表创造力,但-1代表作弊。
Johannes H.

1
哈,但是如果它永不停止,是否“保证它会再次开始”?
杰森C

这就是为什么我说我可能会违反规则。您可以假设无限大的哲学美在于那之后可能发生的一切。图灵机也是如此。
microbian

1
-100是因为我不支持您赢得自己的比赛,尤其是在技术上,但是+101是因为等待它重新开始是有史以来最好的拖延借口。
2014年

好吧,你知道,然后while true; do sleep 1; done碎裂了,不是吗?
2014年

2

重击

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

将其另存为/目录中的repeat.sh并授予其执行权限。可以通过删除文件将其杀死

这是通过在crontab中放置一个条目以在1分钟后运行它来起作用的。


2

Visual Base 6 :)

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

要运行,请创建一个新项目,添加带有此代码的模块,将启动对象设置为“ Sub Main”,进行编译,然后运行可执行文件。


更具可读性的版本:

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

VB6是一个真实的人的VB。最后的同类!
杰森·C


1

重击

比必须的更长,但是我很累,不在乎:)

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

您说它必须在完成后重新启动,而您并没有明确说它必须重复执行或无限期地重新启动。另外,您说过它永远不会有两个实例同时运行。;)

有很多方法可以做到这一点。我个人最喜欢的是做某事,例如在遥远的某个地方发送数据包,然后(通过许多方法)使响应触发该过程。


从技术上讲,该sleep过程在完成时会重新启动
ace_HongKongIndependence

如果该程序是可以自行重新启动的程序,则意味着它必须无限期地重新启动-否则,它正在重新启动并非其自身的其他功能。
杰森C

@Jason C:不必太哲学,就可以重新启动。我们可以辩论真正自我重新启动必须多么复杂,但是我认为这远远超出了作者的意图。但是,如果您希望它真正重新启动,那么可能是使用goto或JMP或您的语言可能提供的任何构造重新开始的事情,因此它本身就是“重新启动”。否则,它只是在执行与自己截然不同的东西。但是随后有人可能会遇到没有真正重启的问题。所以我离题了。
伊恩·向导

1

Android: 1秒后闹钟将重新启动活动

public class AutoRestart extends Activity
{

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

@Override
public void onDestroy() {

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

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

    super.onDestroy();
}

}

1

C + MPI环境

mpifork.c:

#include <stdio.h>

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

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

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

您必须安装OpenMPI或其他一些MPI实现。编译

mpicc -o mpifork mpifork.c

既然我考虑了一下,就没有理由不必使用mpicc-gcc或任何可以使用的编译器了。您只需要拥有mpirun。

gcc -o mpifork mpifork.c

要运行它,您可能应该包括完整的路径名,并包括主机列表。例如,我在/ etc / hosts中添加了一些都指向localhost的条目,并像这样运行它:

/home/phil/mpifork localhost localhost1 localhost2 localhost3 localhost4

可执行文件必须位于要在其上运行该文件的任何计算机上的同一目录中。


本质上,这将获取命令行中提供的主机列表,选择其中一台主机,并使用相同的参数在目标主机上启动可执行文件。如果一切顺利,则mpirun会在不同的机器上(或如果您仅提供'localhost'则在同一台机器上)反复调用自身。可执行文件本身(mpifork)会终止-调用后execvp,它将不再在第一台机器上执行。

如果您想作恶,可以通过在中的命令行中包含主机的完整列表,在每台计算机上启动此命令args。这样一遍又一遍,就可以在每台机器上重新生成其自身的副本-集群前炸弹。

但是,以这种形式,我很确定这可以满足规则。


1

的JavaScript

不需要时无需“进入网络” :-) JavaScript的事件循环调度使我们可以很容易地编写满足给定要求的程序:

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

program将以每秒10次的速度“重新启动”该功能。JavaScript的性质保证了只有一个任务将同时运行,并且不会像“重新加载页面”中那样“重新启动环境”。


0

x86组装

由于它不会产生新的流程,因此不能完全确定这是否符合您的条件,但是无论如何都可以。

该程序将显示一个消息框,分配一些内存,将其自己的代码段复制到分配的内存中,然后跳转到该位置开始循环。它应该一直运行到malloc失败为止。

format PE GUI 4.0
entry a

include 'include/win32a.inc'

section '.text' code readable executable

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

        push    b-a
        call    [malloc]

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

        call    eax
    b:

section '.data' data readable writeable

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

section '.idata' import data readable writeable

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

    import user,\
        MessageBoxA,'MessageBoxA'

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

编译成fasm。


4
由于调用新复制的代码是程序的一部分,因此从技术上讲,您的程序永远不会完成。
microbian

6
从低级的角度来看,这里的所有程序都可以这样说。:-)
Brian Knoblauch 2014年

@BrianKnoblauch我不同意。这里最有趣的答案似乎是在修改系统环境,以便在杀死第一个进程后的某个时间启动该进程的新副本。例如,我认为创建一个chron作业以在将来运行该进程将是让该进程完全终止然后重新启动的好方法。
凯文-恢复莫妮卡

2
@BrianKnoblauch并非如此。进程是操作系统的一种构造(自从1982年286出现保护模式以来,这些进程现在也由硬件通过虚拟地址空间和受保护的内存提供支持)。结束时,所有这些信息都会消失。尽管在挑战中没有明确说明,但我本着挑战的精神表示“重新启动”意味着已分配了新的进程ID。
杰森C

好吧,如果您设法释放内存的话,我会给+1(请在您成功管理后再给我ping操作@,因为我很可能不会关注它)。
2014年

0

Linux新贵init

考虑到对问题的最严格的理解,我认为这是不可能的。从本质上讲,它要求程序在没有其他正在运行的程序的帮助下自发启动。

有一些atchron基础的答案,但最严格的阅读,atd并且anacron是它运行的是所有的时间补充方案,所以他们可能会被取消资格。

一种相关的方法,但稍微低一点的是使用Linux的方法init。以root身份将此.conf文件添加到/etc/init/

描述“永远”

从运行级别开始[2345]
在运行级别上停止[!2345]

重生

高管睡眠10

然后init重新读取其.conf文件:

sudo telinit 5

这将启动一个sleep过程,该过程将持续10秒钟,然后退出。 一旦检测到上一个已消失,init它将重新生成sleep

当然,它仍然init用作补充程序。您可能会说这init是内核的逻辑扩展,并且在任何Linux中都将始终可用。

如果这是不可接受的,那么我想下一步要做的是创建一个重新生成用户空间进程的内核模块(不确定这样做有多容易)。在这里,可以说内核不是进程,因此不是程序(补充程序)。另一方面,从CPU角度来看,内核本身就是一个程序。


-1

TI-BASIC:5个字符

称它为 prgmA

:prgmA

我可以数6个字符。计算TI-BASIC程序大小有什么特别之处吗?
ace_HongKong独立

:只是每当你在TI-BASIC编程的线符号的开始。您输入的不是它,而是在编辑器中。
scrblnrd3

我知道了,谢谢您提供的信息
ace_HongKongIndependence 2014年

那不是递归调用吗?尝试增加A并使用它的值作为基本情况,您最终会发现它逐步退出市场。
ζ--

那么所有变量都是基于ti-basic的全局变量,所以我不确定。可能是
scrblnrd3 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.