2009-04-10 10 views
23

Przechodząc dwa parametry do nowego wątku na puli wątków może być czasami skomplikowane, ale wydaje się, że z wyrażeń lambda i anonimowe metody, mogę to zrobić:ThreadPool.QueueUserWorkItem z wyrażenia lambda i metody anonimowej

public class TestClass 
{ 
    public void DoWork(string s1, string s2) 
    { 
     Console.WriteLine(s1); 
     Console.WriteLine(s2); 
    } 
} 

try 
{ 
    TestClass test = new TestClass(); 
    string s1 = "Hello"; 
    string s2 = "World"; 
    ThreadPool.QueueUserWorkItem(
     o => test.DoWork(s1, s2) 
     ); 
} 
catch (Exception ex) 
{ 
    //exception logic 
} 

teraz już na pewno uprościć ten przykład, ale te punkty są kluczowe:

  • Przedmiotem smyczkowe były przekazywane są niezmienne i dlatego threadsafe
  • S1 i S2 są zmienne zadeklarowane w w zakresie bloku try, który zamykam natychmiast po kolejkowaniu pracy do puli wątków, więc zmienne s1 i s2 nigdy nie są modyfikowane po tym.

Czy coś jest nie tak z tym?

Alternatywą jest utworzenie nowej klasy, która implementuje niezmienny typ z trzema elementami: test, s1 i s2. To wydaje się być dodatkową pracą bez żadnych korzyści w tym momencie.

+1

Dlaczego po prostu nie napiszesz "o => test.DoWork (s1, s2)" zamiast bardziej szczegółowej definicji? –

+0

@Mehrdad: Ponieważ jestem naprawdę nowy w wyrażeniach lambda. ;) - dzięki! –

+0

@Mebron: Zmieniłem go w pytaniu. –

Odpowiedz

16

Nie ma w tym nic złego. Kompilator zasadniczo robi automatycznie to, co opisałeś jako swoją alternatywę. Tworzy klasę przechwytującą przechwycone zmienne (test, s1 i s2) i przekazuje instancję delegata do lambda, która jest przekształcana w metodę na anonimowej klasie. Innymi słowy, jeśli wybierzesz alternatywę, skończysz z soemingiem bardzo podobnym do tego, co kompilator właśnie dla ciebie wygenerował.

2

To miły sposób na zrobienie tego. Nie widzę żadnych wad korzystania z lambdas. Jest prosty i czysty.

4

W tym konkretnym przypadku nie ma tu nic złego. Stan przekazany do drugiego wątku jest całkowicie ograniczony i żaden z typów nie ma żadnych problemów z powinowactwem wątków.

+0

A co z ogólnym wzorem? Skąd wiadomo, że dany typ ma problemy z powinowactwem do wątków? –

+0

Zasadniczo pytasz, czy dana klasa jest bezpieczna dla wątków. W mojej konkretnej implementacji (w większości przypadków) używam głęboko niezmiennych obiektów, aby były bezpieczne dla wątków. Innym sposobem na zabezpieczenie wątków przed obiektami jest użycie blokowania, itp. –

+0

@Joel, jeśli typ ma problemy z powinowactwem do gwintów, wznosisz toast. Nie możesz nic z tym zrobić w osobnym wątku. Ogólny wzór jest jednak dźwiękowy (często go używam). – JaredPar

2

To, na co patrzysz, jest określane jako zamknięcie. Jako chuckj states, kompilator generuje klasę w czasie kompilacji, która odpowiada elementom, do których uzyskuje się dostęp poza zamknięciem.

Jedyna rzecz, o którą musisz się martwić, to to, czy masz parametry ref lub out. Chociaż łańcuchy są niezmienne, odniesienia do nich (lub dowolnej zmiennej) NIE są.

1

Jeden potencjalny problem ze wzoru jest to, że bardzo kuszące, aby go rozwinąć w coś bardziej rodzajowe ale mniej bezpieczny tak (scratch Code nie można oczekiwać, że do pracy):

public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work) 
{ 
    try 
    { 
     T1 param1 = value1; 
     T2 param2 = value2; 
     ThreadPool.QueueUserWorkItem(
      (o) => 
      { 
       work(param1, param2); 
      }); 
    } 
    catch (Exception ex) 
    { 
     //exception logic 
    } 
} 
+0

W moim przypadku mam głęboko niezmienną klasę podstawową, której mogę użyć do przybicia T1 i T2 ... abyś mógł wykonać tę pracę w moim konkretnym przypadku. Jeśli nie rozumiesz problemów z wątkami, to korzystanie z tego wątku i tak nie wchodzi w grę. –

+0

Uzgodnione: twój konkretny przypadek jest w porządku. Kiedy implementujesz to jako ogólny wzór, pojawiają się obawy. –