Recientemente intenté acceder a un cuadro de texto desde un hilo (que no sea el hilo de la interfaz de usuario) y se produjo una excepción. Decía algo acerca de que "el código no es seguro para subprocesos", así que terminé escribiendo un delegado (la muestra de MSDN ayudó) y llamándolo en su lugar.
Pero aun así no entendí por qué todo el código extra era necesario.
Actualización: ¿tendré problemas serios si verifico
Controls.CheckForIllegalCrossThread..blah =true
multithreading
thread-safety
definition
Vivek Bernard
fuente
fuente
Race-Condition
Respuestas:
Eric Lippert tiene una buena publicación de blog titulada ¿Qué es esto que llamas "seguro para subprocesos"? sobre la definición de seguridad del hilo tal como se encuentra en Wikipedia.
3 cosas importantes extraídas de los enlaces:
Definitivamente vale la pena leer!
fuente
En los términos más simples, threadsafe significa que es seguro acceder desde múltiples hilos. Cuando utiliza varios subprocesos en un programa y cada uno intenta acceder a una estructura de datos o ubicación común en la memoria, pueden suceder varias cosas malas. Entonces, agrega un código extra para evitar esas cosas malas. Por ejemplo, si dos personas escribieran el mismo documento al mismo tiempo, la segunda persona que guardará sobrescribirá el trabajo de la primera persona. Para que sea seguro para subprocesos, debe obligar a la persona 2 a esperar a que la persona 1 complete su tarea antes de permitir que la persona 2 edite el documento.
fuente
Wikipedia tiene un artículo sobre seguridad de hilos.
Esta página de definiciones (debe omitir un anuncio, lo siento) lo define así:
Un hilo es una ruta de ejecución de un programa. Un programa de un solo subproceso solo tendrá un subproceso y, por lo tanto, este problema no surge. Prácticamente todos los programas GUI tienen múltiples rutas de ejecución y, por lo tanto, subprocesos: hay al menos dos, uno para procesar la visualización de la GUI y entregar la entrada del usuario, y al menos otro para realizar realmente las operaciones del programa.
Esto se hace para que la interfaz de usuario siga respondiendo mientras el programa funciona descargando cualquier proceso de larga ejecución a cualquier subproceso que no sea de interfaz de usuario. Estos subprocesos pueden crearse una vez y existir durante la vida útil del programa, o simplemente crearse cuando sea necesario y destruirse cuando hayan terminado.
Como estos subprocesos a menudo necesitarán realizar acciones comunes (E / S de disco, resultados de salida en la pantalla, etc.), estas partes del código deberán escribirse de tal manera que puedan manejar llamadas desde múltiples subprocesos, a menudo en al mismo tiempo. Esto implicará cosas como:
fuente
Simplemente, hilo seguro significa que un método o instancia de clase puede ser usado por múltiples hilos al mismo tiempo sin que ocurra ningún problema.
Considere el siguiente método:
Ahora el hilo A y el hilo B desean ejecutar AddOne (). pero A comienza primero y lee el valor de myInt (0) en tmp. Ahora, por alguna razón, el planificador decide detener el hilo A y diferir la ejecución al hilo B. El hilo B ahora también lee el valor de myInt (aún 0) en su propia variable tmp. El subproceso B finaliza todo el método, por lo que al final myInt = 1. Y se devuelve 1. Ahora es el turno del Hilo A nuevamente. El hilo A continúa. Y agrega 1 a tmp (tmp era 0 para el hilo A). Y luego guarda este valor en myInt. myInt es de nuevo 1.
Entonces, en este caso, el método AddOne se llamó dos veces, pero debido a que el método no se implementó de manera segura para subprocesos, el valor de myInt no es 2, como se esperaba, sino 1 porque el segundo subproceso leyó la variable myInt antes de que finalizara el primer subproceso actualizándolo
Crear métodos seguros para subprocesos es muy difícil en casos no triviales. Y hay bastantes técnicas. En Java puede marcar un método como sincronizado, esto significa que solo un hilo puede ejecutar ese método en un momento dado. Los otros hilos esperan en línea. Esto hace que un método sea seguro para subprocesos, pero si hay mucho trabajo por hacer en un método, esto desperdicia mucho espacio. Otra técnica es 'marcar solo una pequeña parte de un método como sincronizado'creando un bloqueo o semáforo, y bloqueando esta pequeña parte (generalmente llamada la sección crítica). Incluso hay algunos métodos que se implementan como seguros para subprocesos sin bloqueo, lo que significa que están construidos de tal manera que múltiples subprocesos pueden atravesarlos al mismo tiempo sin causar problemas, este puede ser el caso cuando solo un método ejecuta una llamada atómica. Las llamadas atómicas son llamadas que no se pueden interrumpir y solo se pueden hacer por un hilo a la vez.
fuente
En el mundo real, el ejemplo para el profano es
Supongamos que tiene una cuenta bancaria con Internet y banca móvil y su cuenta tiene solo $ 10. Realizó el saldo de transferencia a otra cuenta mediante la banca móvil y, mientras tanto, realizó compras en línea utilizando la misma cuenta bancaria. Si esta cuenta bancaria no es segura, entonces el banco le permite realizar dos transacciones al mismo tiempo y luego el banco se declarará en bancarrota.
Threadsafe significa que el estado de un objeto no cambia si simultáneamente varios hilos intentan acceder al objeto.
fuente
Puede obtener más explicaciones del libro "Concurrencia de Java en la práctica":
fuente
Un módulo es seguro para subprocesos si garantiza que puede mantener sus invariantes ante el uso de subprocesos múltiples y concurrencia.
Aquí, un módulo puede ser una estructura de datos, clase, objeto, método / procedimiento o función. Básicamente, un fragmento de código y datos relacionados.
La garantía puede limitarse potencialmente a ciertos entornos, como una arquitectura de CPU específica, pero debe ser válida para esos entornos. Si no hay una delimitación explícita de los entornos, generalmente se supone que implica para todos los entornos que el código se puede compilar y ejecutar.
Los módulos no seguros para subprocesos pueden funcionar correctamente con un uso simultáneo y multiproceso, pero a menudo esto se debe más a la suerte y la coincidencia que al diseño cuidadoso. Incluso si algún módulo no se rompe por debajo, puede romperse cuando se mueve a otros entornos.
Los errores de subprocesos múltiples a menudo son difíciles de depurar. Algunos de ellos solo ocurren ocasionalmente, mientras que otros se manifiestan agresivamente; esto también puede ser específico del entorno. Pueden manifestarse como resultados sutilmente incorrectos o puntos muertos. Pueden desordenar las estructuras de datos de maneras impredecibles y hacer que aparezcan otros errores aparentemente imposibles en otras partes remotas del código. Puede ser muy específico de la aplicación, por lo que es difícil dar una descripción general.
fuente
Hilo de seguridad : un programa seguro de subprocesos protege sus datos de errores de consistencia de memoria. En un programa altamente multiproceso, un programa seguro para subprocesos no causa ningún efecto secundario con múltiples operaciones de lectura / escritura de múltiples subprocesos en los mismos objetos. Diferentes hilos pueden compartir y modificar datos de objetos sin errores de consistencia.
Puede lograr la seguridad del subproceso mediante el uso de API de concurrencia avanzada Esta página de documentación proporciona buenas construcciones de programación para lograr la seguridad del subproceso.
Los objetos de bloqueo admiten modismos de bloqueo que simplifican muchas aplicaciones concurrentes.
Los ejecutores definen una API de alto nivel para lanzar y administrar hilos. Las implementaciones de ejecutor proporcionadas por java.util.concurrent proporcionan una gestión de grupo de subprocesos adecuada para aplicaciones a gran escala.
Las Colecciones concurrentes facilitan la gestión de grandes colecciones de datos y pueden reducir en gran medida la necesidad de sincronización.
Las variables atómicas tienen características que minimizan la sincronización y ayudan a evitar errores de consistencia de la memoria.
ThreadLocalRandom (en JDK 7) proporciona una generación eficiente de números pseudoaleatorios a partir de múltiples hilos.
Consulte los paquetes java.util.concurrent y java.util.concurrent.atomic también para otras construcciones de programación.
fuente
Claramente está trabajando en un entorno WinForms. Los controles de WinForms exhiben afinidad de subprocesos, lo que significa que el subproceso en el que se crean es el único subproceso que se puede utilizar para acceder y actualizarlos. Es por eso que encontrará ejemplos en MSDN y en otros lugares que demuestran cómo ordenar la llamada nuevamente en el hilo principal.
La práctica normal de WinForms es tener un solo hilo dedicado a todo su trabajo de interfaz de usuario.
fuente
Encuentro el concepto de http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 es lo que generalmente considero un subproceso inseguro, que es cuando un método tiene y se basa en un efecto secundario como una variable global.
Por ejemplo, he visto código que formateó números de coma flotante en cadena, si dos de estos se ejecutan en hilos diferentes, el valor global de decimalSeparator se puede cambiar permanentemente a '.'
fuente
Para comprender la seguridad del hilo, lea las secciones a continuación :
fuente