2009-08-25 12 views
6

Digamos que tengo el código¿Los subprocesos están esperando en una cerradura FIFO?

static class ... 
{ 
    static object myobj = new object(); 

    static void mymethod() 
    { 
     lock(myobj) 
     { 
      // my code.... 
     } 
    } 
} 

siguiente Entonces digamos que mientras Thread1 tiene la cerradura thread2 intenta ejecutar MyMethod. ¿Esperará a que se libere el bloqueo o emitirá una excepción?

Si espera, ¿está garantizado el orden de modo que si entran hilos adicionales son FIFO?

Respuesta

8

Actualizado mi respuesta: Están en cola, pero no se garantiza que la orden sea FIFO.

Salida este enlace: http://www.albahari.com/threading/part2.aspx

+4

No necesariamente, consulte: http://stackoverflow.com/questions/961869/is-there-a-synchronization-class-that-guarantee-fifo-order-in-c/961904 –

-1

se va a esperar, y no van a estar en el mismo orden.

Dependiendo de sus necesidades, es posible que tenga un mayor rendimiento si nos fijamos en algo así como un ReaderWriterLock o algo que no sea sólo lock

+1

No son lo mismo orden. –

3

No está claro a partir del código, ¿cómo myobj llegaría a ser visible en el interior mymethod. Parece que var myobj es una variable de pila local en el ámbito de declaración (ya que es var). En ese caso, es posible que cada hilo tenga una instancia separada y el mymethod no se bloqueará.

actualización

Sobre todo el argumento FIFO, alguna información de fondo es necesaria: el CLR no proporciona sincronización. Es el CLR host que proporciona esto como un servicio al tiempo de ejecución de CLR. El host implementa IHostSyncManager y otras interfaces y proporciona las diversas primitivas de sincronización. Esto puede parecer irelevante ya que el host más común es el host de aplicación típico (es decir, usted compila en y exe) y esto no conlleva toda sincronización con el sistema operativo (sus antiguas primitivas de libro de Petzold en Win32 API). Sin embargo, existen al menos otros dos principales entornos de alojamiento: ASP.Net uno (no estoy seguro de lo que esto significa) y SQL Server. Lo que sí puedo decir con certeza es que SQL Server proporciona todas las primitivas en toop del SOS (que básicamente es un usuario más sistema operativo), sin tocar las primitivas del sistema operativo, y las primitivas SOS son injustas por diseño para evitar convoyes de bloqueo (es decir. garantizado sin FIFO). Como ya se señaló en el enlace de la otra respuesta, las primitivas OS también han comenzado a proporcionar un comportamiento injusto, por la misma razón de evitar los convoyes de bloqueo.

Para obtener más información acerca de los convoyes de bloqueo debe leer los artículos Rick Vicik en Designing Applications for High Performance:

bloqueo Convoy

cerraduras FIFO garantizar la equidad y progreso hacia adelante a expensas de causando convoyes de bloqueo . El término destinados originalmente varios hilos ejecutoras la misma parte del código como un grupo resultante en colisiones más altos que si se distribuyeron al azar en todo el código (como automóviles que se agrupan en paquetes por las luces de tráfico).El fenómeno particular del que hablo es el peor porque una vez que forma el traspaso implícito de la propiedad de bloqueo mantiene los hilos en el paso de bloqueo.

Para ilustrar, considere el ejemplo donde un hilo mantiene un bloqueo y se se apropia mientras mantiene el bloqueo. El resultado es que todos los demás hilos se acumularán en la lista de espera para ese bloqueo . Cuando el hilo reemplazado (propietario de la cerradura en este momento) se vuelve a ejecutar y libera la cerradura, transfiere automáticamente la propiedad del cerrojo al primer hilo de la lista de espera . Es posible que ese hilo no se ejecute durante , pero el reloj "tiempo de retención" está en marcha. El dueño anterior por lo general pide al bloqueo de nuevo antes de la lista de espera se borra, perpetuar el convoy

+0

tiene razón, es un objeto estático en un objeto estático, escribí demasiado rápido. Lo arreglaré ahora – Matt

0

Windows y el CLR intentar todo lo posible para garantizar la equidad (el orden FIFO) de la espera. Sin embargo, hay ciertos escenarios donde se puede cambiar el orden de los hilos que esperan en un bloqueo, principalmente en torno a esperas alertables y todos los bloqueos de subprocesos CLR colocan el hilo en estado de alerta.

Para todos los propósitos prácticos, puede suponer que la orden será FIFO; sin embargo, tenga en cuenta este problema.

1

Un ejemplo sencillo nos dice que el orden no se garantiza que sea FIFO

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Diagnostics; 


namespace ConsoleApplication 
{ 
    class Program 
    { 
     private static Info info = new Info(); 

     static void Main(string[] args) 
     { 
      Thread[] t1 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t1[i] = new Thread(info.DoWork); 
      } 

      Thread[] t2 = new Thread[5]; 
      for (int i = 0; i < 5; i++) 
      { 
       t2[i] = new Thread(info.Process); 
      } 

      for (int i = 0; i < 5; i++) 
      { 
       t1[i].Start(); 
       t2[i].Start(); 
      } 

      Console.ReadKey(); 
     } 
    } 

    class Info 
    { 
     public object SynObject = new object(); 

     public void DoWork() 
     { 
      Debug.Print("DoWork Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Thread Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Thread Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 

     public void Process() 
     { 
      Debug.Print("Process Lock Reached: {0}", Thread.CurrentThread.ManagedThreadId); 
      lock (this.SynObject) 
      { 
       Debug.Print("Process Lock Enter: {0}", Thread.CurrentThread.ManagedThreadId); 
       Thread.Sleep(5000); 
       Debug.Print("Process Lock Exit: {0}", Thread.CurrentThread.ManagedThreadId); 
      } 
     } 
    } 
} 

Ejecución procederemos algo como esto

Process Lock Reached: 15 
Process Lock Enter: 15 
DoWork Lock Reached: 12 
Process Lock Reached: 17 
DoWork Lock Reached: 11 
DoWork Lock Reached: 10 
DoWork Lock Reached: 13 
DoWork Lock Reached: 9 
Process Lock Reached: 18 
Process Lock Reached: 14 
Process Lock Reached: 16 
Process Lock Exit: 15 
Thread Lock Enter: 9 
Thread Lock Exit: 9 
Process Lock Enter: 14 
Process Lock Exit: 14 
Thread Lock Enter: 10 
Thread Lock Exit: 10 
Thread Lock Enter: 11 
Thread Lock Exit: 11 
Process Lock Enter: 16 
Process Lock Exit: 16 
Thread Lock Enter: 12 
Thread Lock Exit: 12 
Process Lock Enter: 17 
Process Lock Exit: 17 
Thread Lock Enter: 13 
Thread Lock Exit: 13 
Process Lock Enter: 18 
Process Lock Exit: 18 

Como CA Ver el proceso de bloqueo alcance es diferente que el bloqueo entrar.

Cuestiones relacionadas