una thread the than subproceso que para other llamó interfaz from example diferente created control aplicación aplanó accessed c# multithreading

the - ui thread c#



¿Es una propiedad de cadena en sí misma threadsafe? (5)

Establecer la cadena es una operación atómica, es decir, obtendrá la nueva cadena o la cadena anterior, nunca obtendrá basura.

Si estás haciendo algo de trabajo, por ejemplo

obj.SampleProperty = "Dear " + firstName + " " + lastName;

luego, la concatinación de cadena ocurre antes de la llamada a establecer, por lo tanto, sampleField siempre será la nueva cadena o la anterior.

Sin embargo, si su código de concatenación de cuerda es autorreferencial, por ejemplo

obj.SampleProperty += obj.SampleProperty + "a";

y de lo contrario, en otro hilo tienes

obj.SampleProperty = "Initial String Value";

Entonces necesitas el candado.

Considere que está trabajando con un int. Si está asignando al int, y cualquier valor que obtenga del int es válido, entonces no necesita bloquearlo.

Sin embargo, si el int guarda la cuenta de la cantidad de widgets procesados ​​por dos o más hilos, para que el recuento sea preciso, debe bloquear el int. Es la misma situación para las cuerdas.

Tengo la sensación de que no explique esto muy bien, espero que ayude.

Gracias

BW

Las cadenas en C # son inmutables y seguras en hilos. Pero, ¿qué sucede cuando tienes una propiedad getter pública? Me gusta esto:

public String SampleProperty{ get; private set; }

Si tenemos dos hilos y el primero llama ''get'' y el segundo llama ''set'' al mismo tiempo, ¿qué pasará?

En mi humilde opinión, el conjunto debe hacer un bloqueo para que sea seguro para subprocesos como este:

private string sampleField; private object threadSafer = new object(); public String SampleProperty{ get{ return this.sampleField; } private set{ lock(threadSafer){ sampleField = value; } } }


La mayoría de las respuestas están usando la palabra "atómico" como si los cambios atómicos fueran todo lo que se necesita. No son, por lo general.

Esto se ha mencionado en los comentarios, pero por lo general no en las respuestas, esa es la única razón por la que proporcioné esta respuesta. (El punto sobre el bloqueo en una granularidad más gruesa, para permitir cosas como agregar, es completamente válido también).

Normalmente quiere un hilo de lectura para ver el último valor de la variable / propiedad. Eso no está garantizado por la atomicidad . Como un ejemplo rápido, aquí hay una mala manera de detener un hilo:

class BackgroundTaskDemo { private bool stopping = false; static void Main() { BackgroundTaskDemo demo = new BackgroundTaskDemo(); new Thread(demo.DoWork).Start(); Thread.Sleep(5000); demo.stopping = true; } static void DoWork() { while (!stopping) { // Do something here } } }

DoWork puede funcionar perfectamente, a pesar de que la escritura en la variable booleana es atómica: no hay nada que impida que el JIT guarde en caché el valor de stopping en DoWork . Para solucionar esto, debe bloquear, hacer que la variable sea volatile o utilizar una barrera de memoria explícita. Esto también se aplica a las propiedades de cadena.


La segunda muestra de código definitivamente no es correcta, ya que los bloqueos solo tienen el efecto deseado cuando se usan en todos los lugares donde se accede a la variable (tanto para get como para set), por lo que el get también necesitaría un candado.

Sin embargo, al obtener y configurar un campo de tipo de referencia como una propiedad como esta, agregar una declaración de bloqueo no agrega ningún valor. Se garantiza que las asignaciones a los punteros sean atómicas en el entorno .NET, y si múltiples hilos están cambiando una propiedad, de todos modos tienes una condición de carrera inherente (donde los hilos pueden ver valores diferentes, esto puede o no ser un problema) entonces hay poco señalar en el bloqueo.

Entonces, para lo que hace, la primera pieza de código está bien. Pero si realmente desea construir condiciones de carrera inherentes en una aplicación de subprocesos múltiples es otro asunto.


Un get / set del campo de tipo de referencia (ldfld / stfld) es (IIRC) garantizado como atómico, por lo que no debería existir ningún riesgo de corrupción aquí. Por lo tanto, debería ser seguro para subprocesos desde ese ángulo, pero personalmente bloquearía los datos en un nivel superior, es decir,

lock(someExternalLock) { record.Foo = "Bar"; }

o tal vez:

lock(record.SyncLock) { record.Foo = "Bar"; }

Esto le permite realizar múltiples lecturas / actualizaciones en el mismo objeto como una operación atómica, para que otros subprocesos no puedan obtener un estado de objeto no válido


Esto es seguro para subprocesos sin necesidad de bloqueo. Las cadenas son tipos de referencia, por lo que solo se modifica una referencia a la cadena. Las referencias de un tipo tienen la garantía de ser atómicas (Int32 en sistemas de 32 bits e Int64 en 64 bits).