Aplicaciones que se rompen al reanudar de la suspensión — Cómo funcionan los eventos de energía de Windows y cómo construir aplicaciones empresariales que los sobrevivan

· · Windows, Gestión de energía, Desarrollo en Windows, Aplicaciones empresariales, Control de dispositivos, Investigación de fallos, Win32 API

«Cerré el portátil, lo abrí a la mañana siguiente y la aplicación empresarial estaba llena de errores.» «La aplicación de supervisión de equipos pierde datos solo después de la comida.» «La herramienta residente que exporta a Excel a veces se detiene con un error de conexión.» — Estos tickets comparten un único sospechoso. La suspensión.

Las aplicaciones empresariales de la época en que los PC de escritorio eran la corriente principal se escribieron sobre el supuesto tácito de que «el PC permanece encendido». El campo de batalla principal hoy es el portátil, y por defecto se suspende tras unos minutos de inactividad. En un equipo compatible con Modern Standby, la propia semántica de la suspensión ha cambiado respecto al modelo tradicional. Dirigido a desarrolladores que escriben aplicaciones empresariales y software de control de equipos en Windows, este artículo organiza, a partir de fuentes primarias, qué notifica el sistema operativo a una aplicación antes y después de la suspensión, qué se rompe y cómo escribir una aplicación que sobreviva a la reanudación.

1. Conclusión principal

  • La suspensión es un evento que la aplicación «no tiene derecho a rechazar». Se le notifica justo antes con WM_POWERBROADCAST (PBT_APMSUSPEND), pero el margen de gracia es de unos 2 segundos, y en una suspensión de emergencia la notificación ni siquiera llega.12
  • Al reanudar desde la suspensión llega PBT_APMRESUMEAUTOMATIC y, en una reanudación iniciada por el usuario, llega también PBT_APMRESUMESUSPEND. El trabajo necesario, como reconectar, pertenece por regla general al primero. Las transiciones de entrada y salida del idle de bajo consumo de Modern Standby no siempre se alinean con estas notificaciones, así que trate las notificaciones como una ayuda.34
  • Diseñe bajo el supuesto de que las conexiones TCP, los puertos serie y los identificadores de dispositivo no sobreviven a través de la reanudación. La lógica de reconexión que los reconstruye ante una notificación de reanudación o un error de comunicación es el plato principal.
  • Vigile los temporizadores y el manejo del tiempo. El trabajo periódico se detiene durante la suspensión, y cómo se dispara justo después de reanudar difiere según la API de temporizador y el runtime. También ocurre un «salto enorme del tiempo transcurrido», así que el enfoque seguro es reconstruir la programación al reanudar.
  • Suprima la suspensión de forma explícita en los intervalos por los que no quiere que se suspenda. Use SetThreadExecutionState (ES_SYSTEM_REQUIRED) o una solicitud de energía (PowerSetRequest), y bórrela siempre cuando el trabajo termine.45
  • En un equipo con Modern Standby el sistema sigue ejecutándose de forma intermitente durante la suspensión, pero las aplicaciones de escritorio se pausan. No puede sostener la expectativa de que «nuestra aplicación debería seguir ejecutándose durante la suspensión».6
  • Las herramientas de investigación estándar son powercfg (/requests, /lastwake, /sleepstudy) y Kernel-Power en el registro de eventos.

2. Qué ocurre en torno a la suspensión — El flujo de los eventos de energía

El sistema operativo difunde los cambios de estado de energía a todas las aplicaciones como un mensaje WM_POWERBROADCAST.2 Hay tres eventos principales que involucran la suspensión y la reanudación.

Evento Significado
PBT_APMSUSPEND A punto de entrar en suspensión (la última oportunidad de prepararse)
PBT_APMRESUMEAUTOMATIC Reanudado (llega siempre al reanudar)
PBT_APMRESUMESUSPEND Reanudación causada por una acción del usuario (esta es condicional)

PBT_APMSUSPEND es la notificación justo antes de la suspensión, y aquí puede prepararse cerrando archivos y guardando el estado. Hay, no obstante, dos condiciones. Primero, el tiempo permitido para el procesamiento es de unos 2 segundos por aplicación, y si lo supera el sistema continúa sin esperar.1 Segundo, en una suspensión de emergencia como una batería críticamente baja, se suspende de inmediato sin notificación previa.2 Un diseño que «debe terminar antes de la suspensión» no se sostiene. Trate la notificación como una oportunidad de «hacerlo si llega a tiempo», y ponga el trabajo principal del lado de la reanudación.

El lado de la reanudación son dos etapas. PBT_APMRESUMEAUTOMATIC llega al reanudar desde una transición de suspensión. Encima de eso, si el equipo se reanudó por una acción del usuario como el botón de encendido o una pulsación de tecla (o se detectó la presencia del usuario después), sigue PBT_APMRESUMESUSPEND. A la inversa, una reanudación desatendida por una reactivación remota a través de la red o por mantenimiento entrega solo PBT_APMRESUMEAUTOMATIC.3 Estas dos etapas son en sí mismas una pista de cómo partir el trabajo — haga la recuperación mecánica, como reconstruir conexiones, en PBT_APMRESUMEAUTOMATIC, y las acciones orientadas al usuario, como actualizaciones de pantalla o un aviso de volver a iniciar sesión, en PBT_APMRESUMESUSPEND.

Flujo de notificación de suspensión y reanudaciónPBT_APMSUSPEND llega justo antes de la suspensión con unos 2 segundos de margen; al reanudar, PBT_APMRESUMEAUTOMATIC llega siempre, y PBT_APMRESUMESUSPEND sigue solo en una reanudación iniciada por el usuarioAplicaciónSOAplicaciónSOSuspensión (el código no se ejecuta)PBT_APMSUSPEND (unos 2 segundos de margen)Guardar el estado y cerrar conexionesPBT_APMRESUMEAUTOMATIC (llega al reanudar)Reconectar y restaurar el estadoPBT_APMRESUMESUSPEND (solo reanudación iniciada por el usuario)Actualizaciones de pantalla y otro trabajo orientado al usuario

Figura 1: Las notificaciones son solo «una palabra justo antes, y una o dos palabras después de reanudar». La estrella de la recuperación es el trabajo del lado de la reanudación.

Diferencia entre la suspensión ordinaria y la de emergenciaLa suspensión ordinaria entrega PBT_APMSUSPEND justo antes con unos 2 segundos para prepararse, pero una suspensión de emergencia como batería crítica se detiene sin notificación previa, así que un diseño que depende de la notificación previa no se sostieneSuspensión ordinariaPBT_APMSUSPEND (unos 2 segundos de margen)Prepararse y luego detenerseSuspensión de emergencia (batería crítica)Detenerse sin notificación previaUn diseño que asume que llegará la notificación no se sostiene

Figura 2: Una suspensión de emergencia llega sin aviso. Así que la preparación es «un extra si llega a tiempo», y el trabajo principal va del lado de la reanudación.

Tenga en cuenta que WM_POWERBROADCAST no distingue el tipo de estado de bajo consumo (suspensión frente a hibernación).4 La abstracción correcta para la aplicación es tratarlo como un solo tipo de evento: «se detuvo y volvió». Los servicios sin ventana y las aplicaciones de consola pueden recibir las mismas notificaciones usando RegisterSuspendResumeNotification en forma de devolución de llamada (DEVICE_NOTIFY_CALLBACK).7

Partir el trabajo entre las dos etapas de reanudaciónPonga la recuperación mecánica, como reconectar, en PBT_APMRESUMEAUTOMATIC, que llega al reanudar; ponga el trabajo orientado al usuario, como actualizaciones de pantalla o un aviso de volver a iniciar sesión, en PBT_APMRESUMESUSPEND, que llega solo en una reanudación iniciada por el usuarioPBT_APMRESUMEAUTOMATIC (al reanudar)Recuperación mecánicaPBT_APMRESUMESUSPEND (reanudación iniciada por el usuario)Trabajo orientado al usuarioReconectar y reabrir identificadoresActualizaciones de pantalla y aviso de volver a iniciar sesión

Figura 3: El segundo no llega en una reanudación desatendida, así que poner la recuperación necesaria en el segundo la perderá.

3. Modern Standby — El significado de «suspensión» ha cambiado

Otro hecho moderno que conviene asumir es Modern Standby. La suspensión S3 tradicional era un modelo simple que «detenía el sistema en conjunto»; la suspensión en un equipo con Modern Standby es un modelo al estilo de un smartphone en el que el sistema sigue ejecutándose de forma intermitente después de que se apaga la pantalla.

Lo que importa aquí para una aplicación empresarial es que las aplicaciones de escritorio las pausa el Desktop Activity Moderator (DAM) en la primera etapa de entrar en suspensión.6 El sistema en sí sigue ejecutándose de vez en cuando para mantener la red y recibir notificaciones, pero los componentes que se benefician de eso son los que participan en este mecanismo — el código ordinario de una aplicación de escritorio no se ejecuta. Así que, desde el punto de vista del desarrollador, la conclusión es la misma para Modern Standby y para S3 — diseñe bajo el supuesto de que su código no se ejecuta durante la suspensión.

Diferencia entre la suspensión tradicional y Modern StandbyLa suspensión S3 tradicional detiene el sistema en conjunto, mientras que bajo Modern Standby el sistema sigue ejecutándose de forma intermitente después de que se apaga la pantalla. Las aplicaciones de escritorio las pausa el DAM en ambos casos, así que el código de la aplicación no se ejecutaSuspensión S3 tradicional: se detiene todo el sistemaEl código de la aplicación no se ejecutaModern Standby: el sistema se ejecuta de forma intermitenteLas apps de escritorio las pausa el DAM

Figura 4: El modelo ha cambiado, pero para una aplicación de escritorio la conclusión es la misma: «no puede ejecutarse durante la suspensión».

Otra precaución es lo poco que puede fiarse de las notificaciones. Bajo Modern Standby, las transiciones de entrada y salida del idle de bajo consumo no se alinean con la transición de suspensión tradicional, y una conexión ya puede estar rota sin que llegue nunca una notificación. Trate la notificación de reanudación como una ayuda y ponga la reconexión disparada por la detección de errores (capítulo 5) en la ruta principal de recuperación.

Otra diferencia es la sensación «resbaladiza» del comportamiento. Alcanzar las profundidades de la suspensión es por etapas, y el momento de las desconexiones y las detenciones no es tan nítido como bajo S3. La distinción entre «la pantalla acaba de apagarse» y «se suspendió» también es difícil de ver para el usuario, así que cuando recoja un síntoma necesita confirmar «¿cerraron la tapa?» y «¿cuántos minutos estuvo inactivo?».

4. Qué se rompe — Síntomas clásicos

La conexión TCP está muerta. Durante la suspensión, el interlocutor, el NAT y los firewalls tratan su silencio como un tiempo de espera y descartan la conexión. Peor aún, el socket de este lado no sabe del error, así que falla solo cuando envía o recibe después de reanudar. O, peor todavía, una espera de recepción no falla en absoluto (por eso hace falta un keepalive). Las conexiones de base de datos y los WebSockets tienen la misma forma.

Los identificadores de puerto serie y de dispositivo USB dejan de ser válidos. Un dispositivo conectado por USB puede parecer, al reanudar, como si se hubiera «desenchufado y vuelto a enchufar» una vez, y el identificador que tenía abierto empieza a devolver errores. Ese es el patrón típico de una aplicación de control de equipos que «tiene un error de comunicación solo después de la comida». El diseño de reconexión también se cubre en el artículo de comunicación serie.

Se rompe la continuidad del tiempo. El trabajo impulsado por temporizador, como «sondear cada 10 segundos», no se dispara durante la suspensión. Cómo se dispara justo después de reanudar (el trabajo vencido se dispara una vez de inmediato, no ocurre nada hasta el siguiente periodo, etc.) difiere según la API de temporizador y el runtime que use, así que no deje el manejo de los tics perdidos al comportamiento implícito — el enfoque seguro es reconstruir la programación en la notificación de reanudación. Además, los cálculos de tiempo transcurrido (la diferencia respecto a la marca de tiempo anterior) se convierten de golpe en «el equivalente a 8 horas», y se rompen los cálculos de media o los juicios de tiempo de espera. El trabajo programado, como «ejecutar todas las noches a las 2:00», simplemente no se ejecuta si el PC está suspendido a esa hora (despiértelo con la función de reactivación desde suspensión del Programador de tareas si lo necesita).

Tres formas en que se rompe la continuidad del tiempoEl trabajo periódico se detiene durante la suspensión y el disparo posterior a la reanudación difiere según la API, así que reconstruya la programación al reanudar; la diferencia respecto a la marca de tiempo anterior se vuelve enorme tras reanudar, así que protéjala; el trabajo programado no se ejecuta si el equipo está suspendido, así que considere la reactivación del Programador de tareasTrabajo periódico: se detieneReconstruir la programaciónTiempo transcurrido: explotaProteger diferencias anómalasProgramado: nunca se ejecutóReactivar desde la suspensión

Figura 5: Escriba el manejo de temporizadores y del tiempo bajo el supuesto de que «el tiempo salta». Cada una de las tres formas tiene un tipo de contramedida.

Tres cosas que se rompen a través de la suspensiónA través de la suspensión, una conexión TCP la ha descartado un tiempo de espera del interlocutor, el identificador de un dispositivo USB queda invalidado como una reconexión, y el trabajo basado en tiempo transcurrido observa un salto enorme de tiempo. Recupere cada una con reconexión, reapertura y una guarda de diferenciasIntervalo de suspensiónTCP: el interlocutor la descartó¿USB o tiempo transcurrido?USB: identificador inválidoTiempo transcurrido: un saltoDetectar + reconectarReabrir el dispositivoProteger diferencias anómalas

Figura 6: Lo que se rompe cae en tres familias — «conexiones», «identificadores» y «continuidad del tiempo» — y cada una tiene un tipo de recuperación asentado.

Reautenticación a recursos compartidos. Las unidades de red y las VPN a menudo hay que restablecerlas después de reanudar, y hay un «valle de arranque» de unos pocos a varias decenas de segundos justo después de reanudar en el que el acceso falla. Es más seguro no reintentarlo todo de golpe justo después de reanudar, sino esperar un poco y reintentar por etapas.

5. Construir aplicaciones que sobrevivan a la reanudación

El principio es una sola cosa. Asuma que «las conexiones y los identificadores no sobreviven a través de la suspensión» y estructure la aplicación de modo que siempre pueda recuperarse.

Detecte la reanudación y recupérese. Cuando la WM_POWERBROADCAST de la ventana de nivel superior reciba PBT_APMRESUMEAUTOMATIC, descarte las conexiones que sostiene y reconstruya. El punto es no fiarse solo de la notificación de reanudación. Tanto las notificaciones perdidas como la comunicación que ocurre antes de la notificación son reales, así que emparéjela siempre con una ruta que «reconecta cuando se detecta un error de comunicación», y trate la notificación de reanudación como un disparador que meramente adelanta eso.

// C#: funnel both the resume notification and communication errors into the same reconnect path
protected override void WndProc(ref Message m)
{
    const int WM_POWERBROADCAST = 0x0218;
    const int PBT_APMRESUMEAUTOMATIC = 0x0012;
    if (m.Msg == WM_POWERBROADCAST && (int)m.WParam == PBT_APMRESUMEAUTOMATIC)
    {
        _connectionManager.RequestReconnect();   // idempotent reconnect request
    }
    base.WndProc(ref m);
}

Haga que el propio trabajo de reconexión sea idempotente (seguro no importa cuántas veces se llame), reintente ante un fallo con retroceso exponencial y, en el estado estable, detecte pronto una conexión muerta con un keepalive — ponga esas tres cosas juntas como un conjunto, y sobrevivirá no solo a la reanudación desde la suspensión sino también a una caída breve de la red o al reinicio de un dispositivo.

Diseño de reconexión resistente a la reanudaciónLa notificación de reanudación, un error de comunicación y un fallo de keepalive desembocan todos en el mismo trabajo de reconexión idempotente, que reintenta con retroceso exponencial ante un fallonoNotificación de reanudación (PBT_APMRESUMEAUTOMATIC)Trabajo de reconexión idempotenteDetección de error de comunicaciónFallo de keepalive¿Tuvo éxito?Volver al funcionamiento normalReintentar tras retroceso exponencial

Figura 7: Concentre la reconexión en una sola ruta idempotente y entre en el mismo camino desde la notificación de reanudación, la detección de errores o el keepalive.

Revise el manejo del tiempo. Para el trabajo que usa «el tiempo transcurrido desde la última vez», ponga una guarda que invalide el intervalo cuando detecte una diferencia anormalmente grande (no la pliegue en una media, no la trate como un tiempo de espera). Medir el tiempo transcurrido a través de la reanudación exige mantener la distinción entre un reloj que avanza durante la suspensión (hora de pared) y el tiempo realmente dedicado al trabajo.

Suprima la suspensión de forma explícita en los intervalos por los que no quiere que se suspenda. Durante un trabajo que no debe interrumpirse por suspensión —una migración de datos, comunicación continua con un dispositivo, etc.— puede mantener el sistema despierto con SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) (añada ES_DISPLAY_REQUIRED si también quiere mantener la pantalla encendida).45 Un método más educado es la API de solicitud de energía (PowerCreateRequest + PowerSetRequest), que puede adjuntar una cadena de motivo, y entonces powercfg /requests mostrará «quién lo está bloqueando y por qué».8 Tenga en cuenta que la supresión mediante SetThreadExecutionState es por hilo, y la borra desde el mismo hilo que la fijó. Para trabajo que cambia de hilo, como async/await, use el lado de la solicitud de energía, que se gestiona con un identificador. Hay precauciones. Primero, lo que estas suprimen es la suspensión automática por inactividad. No pueden detener una acción explícita del usuario como cerrar la tapa o elegir Suspender en el menú Inicio, así que no puede saltarse el diseño de reconexión de este capítulo ni siquiera mientras la supresión está activa. Segundo, con batería en un equipo con Modern Standby, estas solicitudes de energía también se cortan un tiempo después de que expire el tiempo de espera de suspensión. El trabajo que no puede interrumpirse debe garantizarse con alimentación de CA o con operaciones.8 Tercero, bólrela siempre cuando el trabajo termine. Una limpieza olvidada se convierte en un error nuevo: «este PC, por alguna razón, no se suspende».

Dos medios de suprimir la suspensiónTanto si usa el cómodo SetThreadExecutionState como la API de solicitud de energía, que puede adjuntar una cadena de motivo y es visible para un administrador mediante powercfg, bórrela siempre cuando el trabajo termineIntervalo de trabajo que no debe suspenderseSetThreadExecutionStateSolicitud de energía (PowerSetRequest)Cómodo — solo marcasCon un motivo — visible en powercfgBórrela siempre cuando el trabajo termine

Figura 8: Para cualquiera de los dos medios, «borrarla cuando termine» es una condición absoluta. Una solicitud de energía que puede hacer visible el motivo es más amable con las operaciones.

Los servicios y las aplicaciones sin ventana reciben notificaciones por devolución de llamada con RegisterSuspendResumeNotification (DEVICE_NOTIFY_CALLBACK).7 Si el funcionamiento continuo es un requisito genuino, la solución de fondo es revisar un diseño que mantiene el trabajo residente en un PC cliente que se suspende, y moverlo al lado servidor o a un equipo operado sin suspensión.

6. Investigación — powercfg y el registro de eventos

La investigación en torno a la energía está bien servida por las herramientas que vienen con el sistema operativo.

  • No se suspende: powercfg /requests enumera los procesos y controladores que han emitido una solicitud de energía. «La aplicación olvidó borrar SetThreadExecutionState» también aparece aquí.
  • Se despierta solo: powercfg /lastwake muestra el motivo de reactivación más reciente, y powercfg /waketimers muestra los temporizadores reservados en ese momento para despertar el equipo.
  • Calidad de Modern Standby: powercfg /sleepstudy genera un informe de consumo de energía y actividad por intervalo de suspensión.9
  • Confirmar la línea de tiempo: El origen Kernel-Power del registro de eventos (Sistema) guarda registros de entrar en suspensión y de reanudación. Contrastarlos con el registro de la aplicación le permite confirmar de forma objetiva si «hubo una reanudación justo antes del error».
Correspondencia entre síntomas de energía y comandos de investigaciónAnte un síntoma de que no se suspende, encuentre quién sostiene una solicitud de energía con powercfg /requests; ante un síntoma de que se despierta solo, encuentre el motivo de reactivación con /lastwake y /waketimers; para una línea de tiempo, use Kernel-Power en el registro de eventosNo se suspendepowercfg /requestsSe despierta solopowercfg /lastwake y /waketimersQuiere confirmar la línea de tiempoKernel-Power en el registro de eventosUna supresión de suspensión olvidada también aparece

Figura 9: Los síntomas se corresponden con comandos de investigación en tres familias. Primero confirme «¿acaba de suspenderse?» y luego parta.

En el manejo de tickets, solo con preguntar primero «¿estaba el PC suspendido justo antes (cerraron la tapa)?» se acelera mucho el aislamiento.

7. Resumen

  • La suspensión no se puede rechazar. La notificación previa (PBT_APMSUSPEND) es de mejor esfuerzo, con unos 2 segundos de margen, y no llega en una emergencia. Ponga el diseño principal del lado de la reanudación.
  • Las notificaciones de reanudación son PBT_APMRESUMEAUTOMATIC (al reanudar desde la suspensión) + PBT_APMRESUMESUSPEND (ante una acción del usuario). Mantenga la reconexión impulsada por errores en la ruta principal para el caso en que la notificación no llegue.
  • Asuma que las conexiones y los identificadores no sobreviven a través de la reanudación, e implemente el conjunto de tres piezas de una reconexión idempotente + retroceso exponencial + un keepalive.
  • Ponga una guarda contra «diferencias anómalas» en el trabajo basado en tiempo transcurrido. Diseñe el trabajo programado bajo el supuesto de que no se ejecuta durante la suspensión.
  • En los intervalos que no deben suspenderse, suprima la suspensión de forma explícita con SetThreadExecutionState o una solicitud de energía, y bórrela siempre cuando termine.
  • La investigación es powercfg (/requests, /lastwake, /sleepstudy) y el registro de eventos Kernel-Power. En el manejo de tickets, pregunte primero «¿se suspendió justo antes?».

Desde el punto de vista de la aplicación, la suspensión es un evento en el que «el tiempo salta sin aviso, se cortan las conexiones con el entorno y luego vuelve». Haber tejido eso en el diseño como parte de la vida cotidiana, y no como una situación anómala, es lo que separa la estabilidad de una aplicación empresarial en la era del portátil.

Artículos relacionados

Áreas de consultoría relacionadas

En KomuraSoft LLC nos encargamos de investigaciones de causa raíz de fallos como «la comunicación se rompe tras reanudar de la suspensión» y «la conexión con el dispositivo se cae después de la comida», de incorporar a posteriori lógica de reconexión y manejo de eventos de energía en aplicaciones existentes, y de revisiones de diseño de aplicaciones empresariales y software de control de equipos que asumen el funcionamiento en portátil.

Referencias

  1. Microsoft Learn, PBT_APMSUSPEND event. Sobre que este es el evento que llega justo antes de que el equipo entre en el estado de suspensión; sobre que se espera que la aplicación termine el trabajo necesario para guardar datos; y sobre que el sistema permite unos 2 segundos para manejar esta notificación, y una aplicación que continúa más allá de eso queda sujeta a interrupción.  2

  2. Microsoft Learn, System Power Management Events. Sobre que el sistema difunde de antemano cambios de modo de funcionamiento como la suspensión; sobre que PBT_APMSUSPEND se notifica antes de la suspensión por inactividad para que pueda prepararse cerrando archivos y guardando datos; sobre que una suspensión de emergencia (batería crítica y similares) no da notificación previa; sobre que el manejo de este mensaje se permite un máximo de 2 segundos por aplicación y se corta tras el tiempo de espera; y sobre que se notifica a todas las aplicaciones al reanudar.  2 3

  3. Microsoft Learn, PBT_APMRESUMESUSPEND event. Sobre que se envía después de PBT_APMRESUMEAUTOMATIC en una reanudación iniciada por el usuario o cuando se detecta entrada del usuario después; sobre que solo se envía PBT_APMRESUMEAUTOMATIC en una reanudación por una causa externa como una reactivación remota; y sobre que se espera que la aplicación reabra los archivos cerrados en el momento de la suspensión y se prepare para la entrada del usuario.  2

  4. Microsoft Learn, WM_POWERBROADCAST message. Sobre que PBT_APMRESUMEAUTOMATIC se envía siempre al reanudar, y PBT_APMRESUMESUSPEND se envía también en una reanudación por entrada del usuario; sobre que este mensaje no distingue el tipo de estado de bajo consumo; sobre que los detalles de las transiciones de estado de energía se registran en el registro de eventos del sistema; y sobre llamar a SetThreadExecutionState para impedir que el sistema entre en un estado de bajo consumo.  2 3 4

  5. Microsoft Learn, SetThreadExecutionState function (winbase.h). Sobre que ES_SYSTEM_REQUIRED y ES_DISPLAY_REQUIRED pueden suprimir la suspensión por inactividad del sistema y el apagado de la pantalla; y sobre declarar la supresión continua con ES_CONTINUOUS y borrarla llamando a ES_CONTINUOUS solo cuando haya terminado.  2

  6. Microsoft Learn, Prepare software for modern standby. Sobre que el Desktop Activity Moderator (DAM) pausa las aplicaciones de escritorio en la primera etapa de la transición a Modern Standby; y sobre que el sistema se mueve después por etapas a una fase de bajo consumo y una fase de resiliencia, con solo los componentes permitidos ejecutándose de forma intermitente.  2

  7. Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). Sobre que esta es la API que registra la recepción de notificaciones de suspensión y reanudación, y sobre indicar DEVICE_NOTIFY_CALLBACK para que una aplicación o un servicio sin ventana pueda recibir la notificación mediante una devolución de llamada, además de la entrega de mensajes a un identificador de ventana.  2

  8. Microsoft Learn, PowerSetRequest function (winbase.h). Sobre poder fijar un tipo de solicitud como mantener despierto el sistema o la pantalla en un objeto de solicitud de energía creado con PowerCreateRequest; sobre poder adjuntar una cadena de motivo de diagnóstico; y sobre que las solicitudes de energía pendientes se pueden enumerar con powercfg /requests.  2

  9. Microsoft Learn, Modern standby SleepStudy. Sobre que el informe generado por powercfg /sleepstudy permite inspeccionar, por intervalo de Modern Standby, el consumo de energía, la actividad y el motivo de reactivación (botón de encendido, entrada del usuario, un temporizador de reactivación, etc.). 

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Puede una aplicación enterarse de la suspensión de antemano y rechazarla?
En el Windows actual puede recibir la notificación, pero no puede rechazarla. Justo antes de la suspensión, un mensaje WM_POWERBROADCAST entrega un evento PBT_APMSUSPEND, y aquí puede prepararse cerrando archivos y guardando el estado, pero el tiempo permitido para el procesamiento es de unos 2 segundos por aplicación, y si lo supera el sistema continúa sin esperar. En una suspensión de emergencia, como una batería críticamente baja, la notificación previa no llega. Por tanto, un diseño que «debe terminar antes de la suspensión» no se sostiene; hace falta un diseño que pueda recuperarse al reanudar, ocurra el corte cuando ocurra. Para un tramo de trabajo por el que de verdad no quiere que se suspenda, suprima la suspensión de forma explícita con SetThreadExecutionState o una solicitud de energía (PowerSetRequest).
¿Cómo detecto que el equipo se ha reanudado?
Si la aplicación tiene una ventana, maneje WM_POWERBROADCAST. Al reanudar desde la suspensión llega PBT_APMRESUMEAUTOMATIC y, si la reanudación la causó una acción del usuario (el botón de encendido o una pulsación de tecla), a continuación llega PBT_APMRESUMESUSPEND. Una reanudación desatendida que vuelve a suspenderse de inmediato entrega solo PBT_APMRESUMEAUTOMATIC, así que la división básica es poner el trabajo necesario, como reconectar, del lado de PBT_APMRESUMEAUTOMATIC, y el trabajo orientado al usuario, como las actualizaciones de pantalla, del lado de PBT_APMRESUMESUSPEND. Los servicios sin ventana y las aplicaciones de consola pueden recibir las mismas notificaciones mediante una devolución de llamada usando RegisterSuspendResumeNotification con DEVICE_NOTIFY_CALLBACK.
¿Puedo mantener la aplicación en ejecución durante la suspensión?
Por regla general, no. Durante la suspensión se detiene la propia ejecución de la CPU (en un equipo con Modern Standby, las aplicaciones de escritorio las pausa el Desktop Activity Moderator), y el código de la aplicación no se ejecuta. Hay dos opciones. Una es suprimir la suspensión solo mientras el trabajo está en curso. Indicar ES_SYSTEM_REQUIRED con SetThreadExecutionState, o emitir una solicitud de energía con PowerCreateRequest/PowerSetRequest, suprime la suspensión automática por inactividad durante ese intervalo (puede confirmarlo con powercfg /requests). Eso no puede detener una acción de suspensión explícita, como que el usuario cierre la tapa, así que sigue haciendo falta estar preparado para la reanudación incluso mientras la supresión está activa. La otra es aceptar la suspensión y diseñar para «ponerse al día después de reanudar». Para trabajo programado, como un lote nocturno, también puede despertar el PC con «Reactivar el equipo para ejecutar esta tarea» del Programador de tareas. El trabajo que de verdad necesita ejecutarse de forma continua pertenece a un servidor o a un servicio configurado para no suspenderse.
¿Por qué las conexiones TCP y los puertos serie dejan de funcionar después de reanudar?
Porque los adaptadores de red y los dispositivos USB también entran en un estado de bajo consumo durante la suspensión. La conexión TCP ya la ha descartado el interlocutor o un tiempo de espera de NAT o de un firewall, y el envío o la recepción después de reanudar devuelve un error (a menudo no se entera hasta que falla). Los adaptadores USB-serie y similares a veces se tratan como una extracción y reinserción del dispositivo al reanudar, y el identificador que tenía abierto deja de ser válido. En ambos casos, el supuesto correcto es que «los identificadores y las conexiones no sobreviven a través de la reanudación», y la respuesta correcta es implementar una lógica de reconexión que reconstruya la conexión ante una notificación de reanudación o un error de comunicación. Combinar un keepalive periódico con reintentos que usan retroceso exponencial ante un fallo es el patrón establecido.
¿Cómo investigo una suspensión inesperada o una reanudación inesperada?
El comando powercfg es la primera herramienta. En la dirección «no se suspende», powercfg /requests enumera qué procesos y controladores han emitido una solicitud de energía que está bloqueando la suspensión. En la dirección «se despierta solo», powercfg /lastwake muestra el motivo de reactivación más reciente y powercfg /waketimers muestra los temporizadores que están reservados en ese momento para despertar el equipo. En un equipo con Modern Standby, powercfg /sleepstudy produce un informe de consumo y actividad durante la suspensión. El historial de suspensión y reanudación también se registra en el registro de eventos (el origen Kernel-Power del registro Sistema), de modo que puede confirmar en una línea de tiempo «cuándo se suspendió, y cuándo y por qué se despertó».

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog