在启动程序B上批量停止程序A,在结束程序B上启动程序A

时间:2018-11-12 00:34:19

标签: batch-file batch-processing

我使用Google的同步程序同步文档。但是,当某些程序打开时,我不希望同步程序与项目文件干涉。我尝试的解决方法如下。

这是一种笨拙的方法,可以在程序B启动时尝试关闭程序A,然后在程序B停止运行时重新打开程序A。下面的批处理脚本有效地做到了这一点,但是它占用了相当大的处理器能力(在我的移动i5 8th gen上为1-4%)。有没有更优雅的方法可以做到这一点?我愿意考虑其他工具(例如AutoIT)。

编辑,根据建议,我在末尾添加了一个简单的15秒超时,这使该程序可以占用大量处理器(即,不是)。通过隐藏的任务计划程序运行它,使它成为可行的解决方案。

@echo off
rem mutually exclusive program enforcer

rem initialize variables
set gDriveOn=init
set reaperOn=init

rem begin infinite loop for monitoring on states
:loopStart

    tasklist /FI "IMAGENAME eq reaper.exe" 2>NUL | find /I /N "reaper.exe">NUL
if "%ERRORLEVEL%"=="0" (
    set reaperOn="TRUE" 
    goto gDrivecheck
    )

rem else if reaper not found
set reaperOn="FALSE"

:gDriveCheck    
    tasklist /FI "IMAGENAME eq googledrivesync.exe" 2>NUL | find /I /N "googledrivesync.exe">NUL
if "%ERRORLEVEL%"=="0" (
    set gDriveOn="TRUE" 
    goto doStuff
    )

rem else if Google Drive not found
set gDriveOn="FALSE"

:doStuff
rem turn off gdrive when reaper is on
if %reaperOn% == "TRUE" (
    if %gDriveOn% == "TRUE" (
        taskkill /f /t /im googledrivesync.exe
        )
    )

if %reaperOn% == "FALSE" (
    if %gDriveOn% == "FALSE" (
        start  C:\"Program Files"\Google\Drive\googledrivesync.exe
        )
    )

rem delay 15 seconds for efficiency
timeout 15
goto :loopStart
)
rem end of infinite loop
)

1 个答案:

答案 0 :(得分:1)

由于发布的源代码未运行,因此我不会尝试回答问题的稳定性部分。请参阅我以前对建议如何自行调试的评论。

关于效果:

批处理文件延迟

如果我什么都没错过,那么这段代码会不断地请求是否存在一对进程。也就是说,它会在上一个检查完成后立即开始下一个检查,一次又一次不间断。

这基本上指示您的计算机将所有可用的处理能力用于检查进程是否存在。该程序理论上应该使用100%CPU,但是由于某种原因,在Windows下列出任务很慢且效率低下,并且您可能拥有一个以上的CPU内核,而批处理本身的速度很慢,因此它只能使用一部分CPU

您很可能不需要经常检查进程。通常每1到10秒执行一次。如果可以接受,则在代码中的某处插入延迟,如下所示:

TIMEOUT /T 5 /NOBREAK

其中5是要等待的秒数。有关更多信息,请参见timeout /?this

AutoIT

在AutoIt中,您将需要ProcessExists()来检查进程是否存在,并且需要Sleep()来插入延迟。使用ProcessClose()杀死进程,然后Run()启动一个进程。该文档位于Function Reference下的here

在Windows上检查进程仍然缓慢且效率低下。 AutoIT文档建议使用the process is polled approximately every 250 milliseconds,这可能意味着如果您尝试更快地请求它,您将获得上次保存的结果,因此插入Sleep(250)或更多是有意义的。

但是,这主要适用于按名称查询进程,该名称请求所有正在运行的进程的列表并在其中搜索您的进程。如果您知道某个进程已经存在,则无需执行此操作-您只需使用其进程ID号(PID)来检查它是否已停止-这样做应该更快。因此,除了ProcessExists("notepad.exe")之外,您还可以这样做:

local $pid = 0
while true
  if ($pid <> 0) then $pid = ProcessExists($pid) ;Process already existed, use PID
  if ($pid = 0) then $pid = ProcessExists("notepad.exe") ;Process did not exist
  if ($pid <> 0) then 
       ;do something if process exists...
  endif
  sleep(300)
  .........
wend

之所以可行,是因为ProcessExists()如果进程存在则返回PID,否则返回0。 如果从上次检查开始就已经知道if,则第一行$pid将开始运行。 如果不是,或者我们之前从未检查过它,或者如果它不再存在但不再存在,则运行第二行并根据进程名称进行检查。对于第二个过程应重复此步骤。请注意,这不是故意if-then-else,因为第一次检查可能会将$pid设置为0

EXE替换

如果上述解决方案不起作用-例如,由于reaper.exe碰巧试图访问某个googledrivesync.exe持有的东西而崩溃,那么可能应该做些其他事情。

一种选择是将reaper.exe重命名为real_reaper.exe并将自动脚本编译成新的reaper.exe,该脚本将杀死googledrivesync并启动real_reaper.exe。该脚本需要传递所有参数,例如

RunWait ('"real_reaper.exe" ' & $CmdLineRaw)

应该可以解决问题。这等待real_reaper.exe完成运行,然后您可以执行Run("googledrivesync.exe")

如果启动reaper.exe的程序使用了一些技巧,则可能无法正常工作,但是在大多数情况下应该可以工作。