_thread — API de bajo nivel para manejo de hilos


Este módulo ofrece primitivas de bajo nivel para trabajar con múltiples threads o hilos (también llamados light-weight processes o tasks) – múltiples hilos de control compartiendo su espacio de datos global. Para sincronizar, provee «candados» simples (también llamados mutexes o binary semaphores). El módulo threading provee una API de manejo de hilos más fácil de usar y de más alto nivel, construida sobre este módulo.

Distinto en la versión 3.7: Este módulo solía ser opcional, pero ahora está siempre disponible.

Este módulo define las siguientes constantes y funciones:

exception _thread.error

Lanzado ante errores específicos de un hilo.

Distinto en la versión 3.3: Ahora es un sinónimo de la excepción incorporada RuntimeError.

_thread.LockType

Este es el tipo de los objetos candado (lock objects).

_thread.start_new_thread(function, args[, kwargs])

Inicia un nuevo hilo y retorna su identificador. El hilo ejecuta la función function con la lista de argumentos args (que debe ser una tupla). El argumento opcional kwargs especifica un diccionario de argumentos por palabras clave.

Cuando la función retorna, el hilo finaliza silenciosamente.

Cuando la función termina con una excepción no gestionada, se invoca a sys.unraisablehook() para que gestione la excepción. El atributo object del argumento gancho (hook), es function. Por defecto, se muestra un seguimiento de pila y luego el hilo sale (pero los otros hilos continúan funcionando).

Cuando la función lanza una excepción SystemExit, se ignora silenciosamente.

Distinto en la versión 3.8: Ahora se utiliza sys.unraisablehook() para gestionar las excepciones no gestionadas.

_thread.interrupt_main()

Simular el efecto de una señal signal.SIGINT que llega al hilo principal. Un hilo puede usar esta función para interrumpir el hilo principal.

Si signal.SIGINT no está gestionada por Python (se definió signal.SIG_DFL o signal.SIG_IGN), esta función no hace nada.

_thread.exit()

Lanza la excepción SystemExit. Cuando no es gestionada, causa que el hilo salga silenciosamente.

_thread.allocate_lock()

Retorna un nuevo objeto candado (lock object). Los métodos de los candados se describen más abajo. El candado está abierto al inicio.

_thread.get_ident()

Retorna el “identificador de hilo” (thread identifier) del hilo actual. Es un entero distinto de cero. Su valor no tiene un significado directo, tiene la intención de ser utilizada como una cookie mágica para, por ejemplo, indexar un diccionario con datos específicos del hilo. Los identificadores de hilo pueden reciclarse cuando un hilo sale y otro se crea.

_thread.get_native_id()

Retorna el ID de hilo nativo integral del hilo asignado por el kernel. Es un entero no-negativo. Su valor puede utilizarse para identificar inequívocamente este hilo en particular en todo el sistema (hasta que el hilo termine, luego de lo cual el valor puede ser reciclado por el Sistema Operativo).

Disponibilidad: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX.

Nuevo en la versión 3.8.

_thread.stack_size([size])

Retorna el tamaño de la pila del hilo (thread stack) utilizada al crear nuevos hilos. El argumento opcional size especifica el tamaño de la pila a utilizar en los hilos que se creen a continuación, y debe ser 0 (utiliza el valor por defecto de la plataforma o el configurado) o un entero positivo de al menos 32768 (32KiB). Si size no se especifica, se utiliza 0. Si no está soportado el cambio del tamaño de pila del hilo, se lanza una excepción RuntimeError. Si la pila especificada es inválida se lanza un ValueError y el tamaño de la pila no se modifica. 32KiB es actualmente el menor valor soportado para el tamaño de la pila, para garantizar suficiente espacio en la misma para que quepa el propio intérprete. Tenga en cuenta que alguna plataformas pueden tener restricciones particulares en los valores para el tamaño de la pila, como requerir un mínimo que supere los 32KiB, o requerir una asignación en múltiplos del tamaño de página de memoria del sistema. Es necesario consultar la documentación de la plataforma para mayor información (son habituales las páginas de 4KiB; usar múltiplos de 4096 para el tamaño de pila es la estrategia sugerida si no se cuenta con información más específica).

Disponibilidad: Sistemas Windows, con hilos POSIX.

_thread.TIMEOUT_MAX

El máximo valor permitido para el parámetro timeout de Lock.acquire(). Especificar un tiempo de espera (timeout) mayor que este valor lanzará una excepción OverflowError.

Nuevo en la versión 3.2.

Los objetos candado (lock objects) tienen los siguientes métodos:

lock.acquire(waitflag=1, timeout=-1)

Sin ningún argumento opcional, este método adquiere el candado incondicionalmente, si es necesario esperando que éste sea liberado por otro hilo (solamente un hilo por vez puede adquirir un candado; para eso existen).

Si el argumento entero waitflag está presente, la acción depende de su valor: si es cero, el candado solamente es adquirido si está disponible de forma inmediata, sin esperas. Mientras que si es distinto de cero, el candado es adquirido sin condiciones, como en el caso anterior.

Si el argumento de punto flotante timeout está presente y es positivo, especifica el tiempo máximo de espera en segundos antes de retornar. Un argumento timeout negativo, especifica una espera ilimitada. No se puede especificar un timeout si waitflag es cero.

El valor de retorno es True si el candado (lock) se adquirió exitosamente, False de lo contrario.

Distinto en la versión 3.2: El parámetro timeout es nuevo.

Distinto en la versión 3.2: La adquisición de candados ahora puede ser interrumpida por señales en POSIX.

lock.release()

Libera el candado. El candado debe haber sido adquirido previamente, pero no necesariamente por el mismo hilo.

lock.locked()

Retorna el estado del candado: True si ha sido adquirido por algún hilo, False de lo contrario.

Además de estos métodos, los objetos candado pueden ser utilizados mediante la declaración with, por ejemplo:

import _thread

a_lock = _thread.allocate_lock()

with a_lock:
    print("a_lock is locked while this executes")

Salvedades:

  • Los hilos interactúan de manera extraña con interrupciones: la excepción KeyboardInterrupt va a ser recibida por un hilo cualquiera. (Cuando el módulo signal está disponible, la interrupción siempre se dirige al hilo principal.

  • Invocar a sys.exit() o lanzar la excepción SystemExit equivale a invocar _thread.exit().

  • No es posible interrumpir el método acquire() en un candado. La excepción KeyboardInterrupt tendrá lugar después de que el candado haya sido adquirido.

  • Cuando el hilo principal sale, ¿sobreviven los otros hilos? Depende de cómo esté definido por el sistema. En la mayoría de los sistemas, los hilos se cierran inmediatamente (killed), sin ejecutar las cláusulas tryfinally o los destructores del objeto.

  • Cuando el hilo principal sale, no hace ninguna de las tareas de limpieza habituales (excepto que se haga honor a las cláusulas tryfinally), y los archivos de E/S estándar no son liberados.