2011-08-01 12 views
14

Jak można użyć czegoś takiego jak ThreadStatic w zadaniu TPL? Moje zrozumienie ("Wrox Professional Parallel Programming with C#", str. 74) jest takie, że Zadanie może przełączać się z jednego wątku na inny podczas wykonywania.ThreadStatic dla zadania TPL

Co chcę zrobić?

Chcę zachować identyfikator sesji wewnątrz klasy statycznej, więc nie muszę przekazywać tego identyfikatora do wszystkich moich metod. Moja biblioteka ma metody takie jak login(id), logout(id) i wiele metod, które działają na poświadczeniach powiązanych z tym id. Ale nie chcę przekazywać tego identyfikatora do każdej metody. Mogę się upewnić, że moja biblioteka jest wywoływana w innym wątku dla różnych sesji. Zapisanie identyfikatora wewnątrz login() w zmiennej zadziała.

Teraz chcę używać zadań TPL, które są tworzone dla mnie przez ThreadPool. Mogę przekazać identyfikator sesji do zadania, ale jeśli przechowuję ten identyfikator wewnątrz zmiennej ThreadStatic, nie przetrwa, jeśli moje zadanie zmieni wątki.

+2

Nie słyszałem o rzeczywistej zadania * przełączanie z jednego wątku do drugiego w trakcie realizacji. Gdzie słyszałeś o tym jako o możliwości? –

+2

Na stronie 74 książki "Wrox Professional Parallel Programming with C#" pokazano rysunek pokazujący przełączanie zadań między wątkami roboczymi. – Gerard

+1

@Gradard: Czy jesteś pewien, że to * podczas wykonywania * zamiast zadania idącego w * kolejce * dla jednego wątku, a następnie kradzieży oznacza przejście do innego wątku do wykonania? –

Odpowiedz

1

Masz rację, gwintowanie statyczne nie nadaje się do zadań.

Lepiej przezwyciężyć problemy z przekazaniem parametru. O wiele lepiej i czystsze jest przekazywanie go. Trochę pisania pozwoli Ci uzyskać większą czytelność i bezpieczeństwo wątków.

+0

Dzięki. To jest to, czego się obawiałem. Muszę nazwać wiele funkcji na wielu poziomach. Tak naprawdę wszystkie moje funkcje wymagają parametru id sesji. Jakieś inne pomysły na rozwiązanie tego problemu? – Gerard

2

Powiedziałbym, że należy unikać wątków statycznych, chyba że masz pewną gwarancję, które zadania są uruchamiane na których wątkach. Po prostu go przepuść. Twoje zamiary będą wyraźniejsze.

4

OC i .NET 4.5 za przepływ asynchroniczny ExecutionContext, co oznacza, że ​​można użyć CallContext.LogicalSetData(string, object) i CallContext.GetLogicalData(string) w taki sam sposób należałoby użyć ThreadStatic. Jednak wiąże się to z istotną karą za wyniki.

Zobacz: Async Causality Chain Tracking, How to include own data in ExecutionContext i ExecutionContext vs SynchronizationContext dla głębszego nurkowania.

Przykład użycia:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Logger.Current = new Logger("Test Printer"); 

     Logger.Current.Print("hello from main"); 
     var t1 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); }); 
     var t2 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); }); 
     Task.WaitAll(t1, t2); 
    } 
} 

class Logger 
{ 
    private string LogName; 

    public Logger(string logName) 
    { 
     if (logName == null) 
      throw new InvalidOperationException(); 

     this.LogName = logName; 
    } 

    public void Print(string text) 
    { 
     Console.WriteLine(LogName + ": " + text); 
    } 

    public static Logger Current 
    { 
     get 
     { 
      return CallContext.LogicalGetData("PrinterName") as Logger; 
     } 
     set 
     { 
      CallContext.LogicalSetData("PrinterName", value); 
     } 
    } 
} 

Wydruki:

 
Test Printer: hello from main 
Test Printer: hello from thread 11 
Test Printer: hello from thread 10 
Powiązane problemy