如何在执行期间从 sleeping/hibernating 停止机器

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

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

然后我希望能够放弃此锁,以便在进程完成后允许机器 sleep/hibernate

我最初的目标是 windows,但跨平台解决方案将是理想的(nix 甚至可以休眠吗?)。

在 Windows,您的第一步是尝试 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

这不是一个完美的解决方案,但我认为这对您来说不是问题:

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

Windows 8 连接待机功能也是您可能需要考虑的事项。查看与电源相关的 API,我们发现 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.

如果您正在处理平板电脑和其他小型设备,那么您可以尝试用 PowerRequestExecutionRequired 调用 PowerSetRequest 来防止这种情况,尽管对它的描述也不理想:

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.

您可能还想使用 ShutdownBlockReasonCreate,但我不确定它是否会阻止 sleep/hibernate。

感谢 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))
        }
    }
}

以上内容已在 Win 7 和 10 上进行测试(尚未在 Win 8 上进行测试 - 假定也可以在其中工作)。

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

以上是我的应用程序的明智行为。