# `_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(signum=signal.SIGINT, /)

  Simular el efecto de una señal que llega al hilo principal. Un hilo puede usar esta función para interrumpir el hilo principal, aunque no hay garantías de que la interrupción ocurrirá inmediatamente.

  If given, signum is the number of the signal to simulate. If signum is not given, `signal.SIGINT` is simulated.

  If the given signal isn’t handled by Python (it was set to `signal.SIG_DFL` or `signal.SIG_IGN`), this function does nothing.

  Distinto en la versión 3.10: Se agrega el argumento signum para personalizar el número de señal.

  Nota

  Esto no emite la señal correspondiente, sino que programa una llamada al controlador asociado (si existe). Si realmente se quiere emitir la señal, se utiliza `signal.raise_signal()`.

_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: Windows, hilos POSIX (también llamados pthreads).

  Unix platforms with POSIX threads support.

_thread.TIMEOUT_MAX

  The maximum value allowed for the timeout parameter of `Lock.acquire`. Specifying a timeout greater than this value will raise an `OverflowError`.

  Nuevo en la versión 3.2.

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

lock.acquire(blocking=True, 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 blocking está presente, la acción depende de su valor: si es False, el candado es adquirido sólo si puede ser adquirido inmediatamente sin espera, en cambio si es True, el candado es adquirido incondicionalmente como arriba.

  Si el argumento de punto flotante timeout está presente y es positivo, éste 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 blocking es False.

  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()`.

- It is not possible to interrupt the `acquire()` method on a lock — the `KeyboardInterrupt` exception will happen after the lock has been acquired.

- 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 `try` … `finally` 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 `try` … `finally`), y los archivos de E/S estándar no son liberados.