2011-05-27 14 views
8

Publico mi comprensión del bloqueo de C# de la siguiente manera, ayúdenme a validar si lo hago bien o no.Uso de la palabra clave de bloqueo C#

public class TestLock 
{ 
    private object threadLock = new object(); 
    ... 
    public void PrintOne() 
    { 
     lock (threadLock) 
     { 
      // SectionOne 
     } 
    } 

    public void PrintTwo() 
    { 
     lock (threadLock) 
     { 
      // SectionTwo 
     } 
    } 
    ... 
} 

Caso I> Thread1 y Thread2 al mismo tiempo trato de llamar Printone. Dado que PrintOne está protegido por el bloqueo de instancia, en cualquier momento, solo un hilo puede entrar exclusivamente en SectionOne.

¿Es esto correcto?

Caso II> Thread1 y Thread2 al mismo tiempo tratar de llamar Printone y PrintTwo respectivamente (es decir Thread1 llama Printone y Thread2 llama PrintTwo) ya que dos métodos de impresión son vigiladas por la misma cerradura ejemplo, en cualquier momento, solo un hilo puede acceder de forma exclusiva a SectionOne o SectionTwo, pero NO a ambos.

¿Es esto correcto?

+1

Para resumir las respuestas a continuación: el código es seguro para subprocesos por única instancia. Cuando las instancias comparten recursos, @oleski tiene la respuesta correcta (= No) –

+0

Y por lo tanto -1 por no incluir los datos/recursos compartidos. Por favor edita. –

+2

Es un punto válido, pero la pregunta original no dice si las instancias están separadas o no y, por lo tanto, por la forma en que se escribe el código/pregunta, era seguro asumir que estaba hablando de las llamadas realizadas contra la misma instancia . Por lo tanto, no estoy de acuerdo con su voto negativo, pero esa es su expectativa. –

Respuesta

1

Sí y sí. Los casos son correctos.

+0

código no es seguro – oleksii

+0

@oleksii: como dijiste, solo por instancia segura. Sin embargo, OP escrito sobre bloqueo de instancia. –

+0

Supongo que @Henk tiene sentido, la pregunta era vaga sobre este tema en particular – oleksii

1

Caso I: Marque ✓

Caso II: Asegúrate ✓

No se olvide que el bloqueo es sólo una forma de sincronización de subprocesos. Para otros métodos userfull, debe decir: Thread Synchronization

Directamente de la muestra de MSDN:

public class TestThreading 
{ 
    private System.Object lockThis = new System.Object(); 

    public void Process() 
    {  
     lock (lockThis) 
     { 
      // Access thread-sensitive resources. 
     } 
    }  
} 
+4

Mi recomendación: http://www.albahari.com/threading/ –

+0

objeto de bloqueo no es estático, el código no es seguro – oleksii

+0

@Teoman por favor intente con mi código de muestra y obtendrá un archivo IOException es usado. Yo creo que es un caso válido. El objeto de bloqueo ** debe ** ser estático. Si dos subprocesos utilizan instancias diferentes de la clase, habrá dos instancias de bloqueo y el código se volverá inseguro. – oleksii

1

Tu conocimiento es 100% correcto. Entonces, si, por ejemplo, desea permitir la entrada en los dos métodos por separado, le conviene tener dos bloqueos.

+0

+1 para _ "para permitir la entrada en los dos métodos por separado, es posible que desee tener dos bloqueos" _ –

6

1 y 2 son verdadero solo si todos sus hilos usan la misma instancia de la clase. Si utilizan instancias diferentes, a continuación, ambos casos son falsa

Muestra

public class TestLock 
{ 
    private object threadLock = new object(); 

    public void PrintOne() 
    { 
     lock (threadLock) 
     { 
      Console.WriteLine("One"); 
      var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource 
      f.Close(); 
     } 
    } 

    public void PrintTwo() 
    { 
     lock (threadLock) 
     { 
      Console.WriteLine("Two"); 
      var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource 
      f.Close(); 
     } 
    } 
} 

Y código de prueba

static void Main(string[] args) 
{ 
    int caseNumber = 100; 

    var threads = new Thread[caseNumber]; 
    for (int i = 0; i < caseNumber; i++) 
    { 
     var t = new Thread(() => 
           { 
            //create new instance 
            var testLock = new TestLock(); 
            //for this instance we safe 
            testLock.PrintOne(); 
            testLock.PrintTwo(); 
           }); 
     t.Start(); 
     //once created more than one thread, we are unsafe 
    } 
} 

Una de las posibles soluciones es añadir una palabra clave estática a la declaración de objeto de bloqueo y métodos que lo utilizan.

private static object threadLock = new object(); 

ACTUALIZACIÓN Buen punto hecha por konrad.kruczynski

... "hilo de seguridad", también se asume desde contexto.Por ejemplo, podría tomar su código de apertura de archivo y también generar excepción con bloqueo estático - simplemente tomando otra aplicación dominio. Y, por lo tanto, propongo que OP use clase Mutex en todo el sistema o así. Por lo tanto, el caso estático se deduce como el de instancia.

+0

El código es seguro para hilos _per instance_. El OP menciona "bloqueo de instancia" una vez, pero es impreciso sobre lo que realmente se comparte. –

+0

@Henk Estoy de acuerdo, mencionó el bloqueo de instancia, actualizará mi respuesta. tnx. – oleksii

+3

el rendimiento de bloqueo está muy directamente relacionado con la cantidad de contención que hay para el bloqueo. Entonces, realmente no deberías usar un bloqueo estático a menos que estés modificando datos estáticos y si estás usando un bloqueo estático no debes usarlo excepto para proteger los datos estáticos. – Yaur

0

aquí están los fundamentos (más o menos)

1) utilizar bloqueos de instancia para datos de instancia

public class InstanceOnlyClass{ 
    private int callCount; 
    private object lockObject = new object(); 

    public void CallMe() 
    { 
     lock(lockObject) 
     { 
      callCount++; 
     } 
    } 
} 

2) utilizar bloqueos estáticos para datos estáticos

public class StaticOnlyClass{ 
    private int createdObjects; 
    private static object staticLockObject = new object(); 

    public StaticOnlyClass() 
    { 
     lock(staticLockObject) 
     { 
      createdObjects++; 
     } 
    } 
} 

3) si está protegiendo datos estáticos y de instancia, utilice bloqueos estáticos y de instancia separados

public class StaticAndInstanceClass{ 
    private int createdObjects; 

    private static object staticLockObject = new object(); 

    private int callCount; 

    private object lockObject = new object(); 

    public StaticAndInstanceClass() 
    { 
     lock(staticLockObject) 
     { 
      createdObjects++; 
     } 
    } 

    public void CallMe() 
    { 
     lock(lockObject) 
     { 
      callCount++; 
     } 
    } 
} 

en base a este código es muy bien si usted está accediendo a datos de instancia, pero no seguro si está modificando los datos estáticos

Cuestiones relacionadas