如何阻止计算机在执行期间进入睡眠/休眠状态

huangapple go评论108阅读模式
英文:

How to to stop a machine from sleeping/hibernating for execution period

问题

我有一个使用golang编写的应用程序(部分),作为其操作的一部分,它将生成一个外部进程(用c编写)并开始监视。这个外部进程可能需要几个小时才能完成,所以我正在寻找一种方法,在处理过程中防止计算机进入睡眠或休眠状态。

然后,我希望能够释放这个锁,这样当进程完成时,计算机就可以进入睡眠/休眠状态。

我最初的目标是Windows,但跨平台的解决方案会更理想(nix是否支持休眠?)。

英文:

I have an app written in golang (partially), as part of its operation it will spawn an external process (written in c) and begin monitoring. This external process can take many hours to complete so I am looking for a way to prevent the machine from sleeping or hibernating whilst processing.

I would like to be able to then relinquish this lock so that when the process is finished the machine is allowed to sleep/hibernate

I am initially targeting windows, but a cross-platform solution would be ideal (does nix even hibernate?).

答案1

得分: 3

感谢Anders指导我正确的方向-我在golang中编写了一个最小的示例(见下文)。

注意:重置计时器的轮询似乎是唯一可靠的方法,我发现当尝试与连续标志结合时,它只会在大约30秒内生效(不知道为什么),话虽如此,在这个示例中进行轮询是过度的,可能可以增加到10分钟(因为最小休眠时间为15分钟)

另外,这是一个特定于Windows的示例:

package main

import (
	"log"
	"syscall"
	"time"
)

// Execution States
const (
	EsSystemRequired = 0x00000001
	EsContinuous     = 0x80000000
)

var pulseTime = 10 * time.Second

func main() {
	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	setThreadExecStateProc := kernel32.NewProc("SetThreadExecutionState")

	pulse := time.NewTicker(pulseTime)

	log.Println("Starting keep alive poll... (silence)")
	for {
		select {
		case <-pulse.C:
			setThreadExecStateProc.Call(uintptr(EsSystemRequired))
		}
	}
}

以上代码在Windows 7和10上经过测试(尚未在Windows 8上测试-预计在那里也能工作)。

任何用户请求休眠都会覆盖此方法,包括关闭笔记本电脑盖子等操作(除非更改了电源管理设置)。

以上是我应用程序的合理行为。

英文:

Thanks to Anders for pointing me in the right direction - I put together a minimal example in golang (see below).

Note: polling to reset the timer seems to be the only reliable method, I found that when trying to combine with the continuous flag it would only take effect for approx 30 seconds (no idea why), having said that polling on this example is excessive and could probably be increased to 10 mins (since min hibernation time is 15 mins)

Also FYI this is a windows specific example:

package main

import (
	&quot;log&quot;
	&quot;syscall&quot;
	&quot;time&quot;
)

// Execution States
const (
	EsSystemRequired = 0x00000001
	EsContinuous     = 0x80000000
)

var pulseTime = 10 * time.Second

func main() {
	kernel32 := syscall.NewLazyDLL(&quot;kernel32.dll&quot;)
	setThreadExecStateProc := kernel32.NewProc(&quot;SetThreadExecutionState&quot;)

	pulse := time.NewTicker(pulseTime)

	log.Println(&quot;Starting keep alive poll... (silence)&quot;)
	for {
		select {
		case &lt;-pulse.C:
			setThreadExecStateProc.Call(uintptr(EsSystemRequired))
		}
	}
}

The above is tested on win 7 and 10 (not tested on Win 8 yet - presumed to work there too).

Any user request to sleep will override this method, this includes actions such as shutting the lid on a laptop (unless power management settings are altered from defaults)

The above were sensible behaviors for my application.

答案2

得分: 1

在Windows上,你的第一步是尝试使用SetThreadExecutionState函数:

> 该函数允许应用程序通知系统它正在使用中,从而防止系统在应用程序运行时进入睡眠或关闭显示器。

这不是一个完美的解决方案,但我假设这对你来说不是一个问题:

> SetThreadExecutionState函数不能阻止用户将计算机置于睡眠状态。应用程序应该尊重用户在关闭笔记本电脑盖子或按下电源按钮时期望的某种行为。

Windows 8的连接待机功能也是你可能需要考虑的。在与电源相关的API中,我们找到了关于PowerRequestSystemRequired的描述:

> 在用户不活动一段时间后,系统继续运行而不是进入睡眠状态。
>
> 在支持连接待机的系统上,不会响应此请求类型。应用程序应改用PowerRequestExecutionRequired请求。

如果你正在处理平板电脑和其他小型设备,你可以尝试使用PowerSetRequest函数,并将其设置为PowerRequestExecutionRequired,以防止系统进入睡眠状态,尽管该函数的描述也不是很理想:

> 调用进程将继续运行,而不会被进程生命周期管理机制挂起或终止。进程被允许运行的时间和持续时间取决于操作系统和电源策略设置。

你可能还想使用ShutdownBlockReasonCreate函数,但我不确定它是否会阻止睡眠/休眠。

英文:

On Windows, your first step is to try SetThreadExecutionState:

> Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running

This is not a perfect solution but I assume this is not an issue for you:

> The SetThreadExecutionState function cannot be used to prevent the user from putting the computer to sleep. Applications should respect that the user expects a certain behavior when they close the lid on their laptop or press the power button

The Windows 8 connected standby feature is also something you might need to consider. Looking at the power related APIs we find this description of PowerRequestSystemRequired:

> The system continues to run instead of entering sleep after a period of user inactivity.
>
> This request type is not honored on systems capable of connected standby. Applications should use PowerRequestExecutionRequired requests instead.

If you are dealing with tablets and other small devices then you can try to call PowerSetRequest with PowerRequestExecutionRequired to prevent this although the description of that is also not ideal:

> The calling process continues to run instead of being suspended or terminated by process lifetime management mechanisms. When and how long the process is allowed to run depends on the operating system and power policy settings.

You might also want to use ShutdownBlockReasonCreate but I'm not sure if it blocks sleep/hibernate.

huangapple
  • 本文由 发表于 2017年8月1日 19:09:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/45436158.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定