2012-10-17 18 views
7

Jeśli istnieje wiele wątków, wszystkie oczekujące na tę samą blokadę, to możliwe, że gwinty główne mają wyższy priorytet w uzyskaniu blokady. Oznacza to, że jeśli wątki robocze przechodzą do instrukcji lock przed głównym wątkiem, główny wątek uzyskałby blokadę przed innymi wątkami, które już na nim czekały.C# czy można zmienić priorytet uzyskania blokady?

Odpowiedz

7

Nie, instrukcja lock mapuje na System.Threading.Monitor.Enter() (MSDN) i nie ma przeciążenia, które akceptuje parametr priorytetu.

Najbliższą rzeczą, o jakiej mogę myśleć, to ReaderWriterLock (Slim), ale poważnie zastanowiłbym się nad projektem, który prowadzi do tej prośby. Prawdopodobnie istnieją lepsze sposoby osiągnięcia tego, czego potrzebujesz.

2

Poprzez natywną instrukcję blokady, nie. Dzięki własnemu własnemu mechanizmowi blokowania, na pewno, jeśli chcesz poświęcić czas i wysiłek, aby go rozwinąć.

Oto mój szkic rozwiązania. Może, ale nie musi działać, i może nie być super efektywny, ale jest to co najmniej miejsce początkowe:

public class Lock 
{ 
    bool locked = false; 

    private object key = new object(); 
    SortedDictionary<int, Queue<ManualResetEvent>> notifiers = 
     new SortedDictionary<int, Queue<ManualResetEvent>>(); 

    ManualResetEvent specialNotifier = null; 

    public void Lock() 
    { 
     lock (key) 
     { 
      if (locked) 
      { 
       ManualResetEvent notifier = new ManualResetEvent(false); 

       int priority = getPriorityForThread(); 

       Queue<ManualResetEvent> queue = notifiers[priority]; 
       if (queue == null) 
       { 
        queue = new Queue<ManualResetEvent>(); 
        notifiers[priority] = queue; 
       } 

       queue.Enqueue(notifier); 

       notifier.WaitOne(); 
      } 
      else 
      { 
       locked = true; 
      } 
     } 
    } 

    private static int getPriorityForThread() 
    { 
     return 0; 
    } 

    public void Release() 
    { 
     lock (key) 
     { 
      foreach (var queue in notifiers.Values) 
      { 
       if (queue.Any()) 
       { 
        var notifier = queue.Dequeue(); 
        notifier.Set(); 
        return; 
       } 
      } 
      locked = false; 
     } 
    } 
} 
+0

tylko ciekaw, czy istnieje jakikolwiek powód, to nie może używać IDisposable? – wwahammy

+0

@wwahammy Nie ma powodu, nie. – Servy

1

Oto inne rozwiązanie. Mam wiele linii, ale jest to całkiem proste. Funkcja DoSomethingSingle będzie wywoływana tylko jeden wątek na raz, a preferowane będą te z flagą highPriority.

static int numWaiting = 0; 
    static object single = new object(); 

    ResultType DoSomething(string[] argList, bool highPriority = false) 
    { 
     try 
     { 
      if (highPriority) 
      { 
       Interlocked.Increment(ref numWaiting); 
      } 

      for (;;) 
      { 
       lock (single) 
       { 
        if (highPriority || numWaiting == 0) 
        { 
         return DoSomethingSingle(argList); 
        } 
       } 
       // Sleep gives other threads a chance to enter the lock 
       Thread.Sleep(0); 
      } 
     } 
     finally 
     { 
      if (highPriority) 
      { 
       Interlocked.Decrement(ref numWaiting); 
      } 
     } 
    } 

Umożliwia to dwa poziomy priorytetu. Gwarantuje, że wątek o niskim priorytecie uzyska dostęp do zasobu tylko wtedy, gdy oczekują na niego wątki o wysokim priorytecie.

edit: zmiana blokady INCR/DEC

Powiązane problemy