2009-02-04 20 views
8

¿Las variables "booleanas" son seguras para subprocesos para leer y escribir desde cualquier subproceso? He visto algunas referencias de grupos de noticias para decir que sí. ¿Hay algún otro tipo de datos disponible? (¿Tipos enumerados, quizás intes cortos?)Lista de tipos de datos Delphi con operaciones de lectura/escritura 'thread-safe'?

Sería bueno tener una lista de todos los tipos de datos que se pueden leer con seguridad desde cualquier hilo y otra lista que también se puede escribir en cualquier hilo sin tener que recurrir a varios métodos de sincronización.

Respuesta

7

Tenga en cuenta que puede hacer esencialmente todo en delphi unthreadsafe. Mientras que otros mencionan problemas de alineación en booleano esto oculta de alguna manera el problema real.

Sí, puede leer un valor booleano en cualquier hilo y escribir en un booleano en cualquier hilo si está alineado correctamente. Pero leer de un booleano que cambie no necesariamente es "seguro para subprocesos" de todos modos. Supongamos que tiene un booleano que establece en verdadero cuando ha actualizado un número para que otro hilo lea el número.

if NumberUpdated then 
begin 
    LocalNumber = TheNumber; 
end; 

Debido a las optimizaciones del procesador hace Thenumber puede leerse antes de leer NumberUpdated, por tanto, es posible obtener el valor antiguo de Thenumber eventhough informado NumberUpdated pasado.

Aka, su código puede llegar a ser:

temp = TheNumber; 
if NumberUpdated the 
begin 
    LocalNumber = temp; 
end; 

En mi humilde opinión, una regla básica:
". Lee es seguro para subprocesos escrituras no es seguro para subprocesos"
Así que si va a hacer una escritura proteger los datos con la sincronización en todas partes lee el valor mientras se puede escribir potencialmente.
Por otro lado, si solo lee y escribe un valor en un hilo, entonces es seguro para subprocesos. Entonces puede hacer una gran cantidad de escritura en una ubicación temporal, luego sincronizar una actualización de los datos de toda la aplicación.

Bonus propaganda:

El VCL no es hilo de seguridad. Mantenga todas las modificaciones de cosas ui en el hilo principal. Mantenga la creación de todas las cosas de la interfaz de usuario en el hilo principal también.

Muchas funciones tampoco son seguras para hilos, mientras que otras sí lo son, a menudo depende de las llamadas a winapi subyacentes.

No creo que una "lista" sea útil, ya que "thread safe" puede significar muchas cosas.

+0

+1, muy buenos puntos. Para cualquier persona interesada, consulte, por ejemplo, http://en.wikipedia.org/wiki/Memory_barrier y la información vinculada. – mghie

5

En la arquitectura de 32 bits, solo los tipos de datos de 32 bits o menos alineados correctamente deben considerarse atómicos. Los valores de 32 bits deben estar alineados en 4 (la dirección de los datos debe ser divisible por cuatro). Probablemente no te topes con el intercalado a un nivel tan ajustado, pero teóricamente podrías tener doble, Int64 o escritura no atómica extendida.

+0

Durante mucho tiempo, la lectura/escritura de 64 bits alineada ha sido atómica en el hardware x86, incluso en el modo de 32 bits –

+0

Desde la introducción de arquitecturas multinúcleo y multiprocesador, la alineación ya no es una garantía. Una vez probé esto por mí mismo con algunos hilos extremadamente cortos que martillaban los datos adecuadamente alineados con las escrituras, mientras que otros hilos intentaban leerlos. Los lectores fueron codificados para plantear excepciones cuando los valores leídos no estaban en un conjunto de valores que los escritores estaban escribiendo. –

7

No se trata de tipos de datos que sean seguros para subprocesos, pero se trata de qué hacer con ellos. Sin bloqueo ninguna operación es segura para subprocesos que implica cargar un valor, luego cambiarlo y luego escribirlo de nuevo: incrementar o disminuir un número, borrar o establecer un elemento en un conjunto; no todos son seguros para subprocesos.

Hay una serie de funciones que permiten operaciones atómicas: incremento enclavado, decremento entrelazado e intercambio entrelazado. Este es un concepto común, nada específico de Windows, x86 o Delphi. Para Delphi puede usar las funciones InterlockedFoo() de la API de Windows, también hay varias envolturas alrededor de ellas. O escribe el tuyo Las funciones operan en enteros, por lo que puede tener incrementos atómicos, decrementos e intercambios de enteros (32 bits) con ellos.

También puede usar operaciones de ensamblaje y prefijo con el prefijo de bloqueo.

Para obtener más información, consulte también this StackOverflow pregunta.

0

El código Indy contiene algunos tipos de datos de seguridad atómica/hilo en IdThreadSafe.pas:

  • TIdThreadSafeInteger
  • TIdThreadSafeBoolean
  • TIdThreadSafeString
  • TIdThreadSafeStringList y algo más ...
1

Con procesamiento RISC multi-núcleo y núcleo separado c Debido a que la memoria está en la mezcla de un procesador moderno, ya no es el caso de cualquier construcción de lectura o escritura de lenguaje de alto nivel "trivial" (o para eso, muchas instrucciones de ensamblaje "atómicas" de 8086 una vez a la vez)) puede considerarse atómico. De hecho, a menos que una instrucción de ensamblador esté específicamente diseñada para ser atómica, probablemente no sea atómica, y eso incluye la mayoría de los mecanismos para la lectura de memoria. Incluso una lectura de entero largo en el nivel de ensamblador puede corromperse mediante una escritura simultánea de otro núcleo de procesador que comparte la misma memoria y el uso de acciones de actualización de caché asíncrona en el nivel del procesador RISC. Recuerde que en un procesador que comprende múltiples núcleos RISC, incluso las instrucciones de lenguaje ensamblador son en realidad instrucciones de código de "nivel superior". Nunca se sabe exactamente cómo se implementan en el nivel de bits, y puede que no sea exactamente lo que esperaba si estuviera leyendo un viejo manual de ensamblador 8086 (de un solo núcleo). Windows proporciona operadores atómicos compatibles con el sistema nativo, y se recomienda utilizarlos en lugar de hacer suposiciones básicas sobre las operaciones atómicas.

¿Por qué utilizar los operadores de Windows? Debido a que una de las primeras cosas que Windows hace es establecer en qué máquina se está ejecutando. Uno de los aspectos clave que asegura que funciona correctamente es qué operaciones atómicas existen y cómo funcionarán. Si desea que su código funcione bien en el futuro con cualquier procesador futuro, puede duplicar (y actualizar constantemente) todo este esfuerzo en su propio código, o puede aprovechar el hecho de que Windows ya lo hizo todo al inicio. A continuación, incorporó el código necesario en su API en tiempo de ejecución.

Lea las páginas de MSDN sobre operaciones atómicas. La API de Windows los muestra para usted. A veces pueden parecer torpe o torpe, pero son a prueba de futuro y siempre van a funcionar exactamente como dice en la lata.

¿Cómo puedo saber esto? Bueno, porque si no lo hicieran, entonces no podrían ejecutar Windows. Parada completa No importa ejecutar tu propio código.

Siempre que escriba código, siempre es una buena idea entender Parsimony y considerar Occam's razor. En otras palabras, si Windows ya lo hace, y su código necesita que Windows se ejecute, entonces use lo que Windows ya hace, en lugar de probar muchas soluciones hipotéticas alternativas y cada vez más complejas que pueden funcionar o no. Hacer cualquier otra cosa es solo una pérdida de tiempo (a menos, por supuesto, que sea en lo que te encuentres).