Подтвердить что ты не робот

ThreadPool.QueueUserWorkItem с выражением лямбда и анонимным методом

Передача двух параметров в новый поток в threadpool иногда может быть сложной, но, похоже, что с лямбда-выражениями и анонимными методами я могу это сделать:

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
}

Теперь я, конечно, упростил этот пример, но эти точки являются ключевыми:

  • Передаваемые объекты строки неизменяемы и, следовательно, потокобезопасны
  • Переменные s1 и s2 объявляются в пределах области try, которые я выхожу сразу же после очередности работы в пул потоков, поэтому переменные s1 и s2 никогда не изменяются после этого.

С этим что-то не так?

Альтернативой является создание нового класса, который реализует неизменяемый тип с тремя членами: test, s1 и s2. Это просто похоже на дополнительную работу без каких-либо преимуществ на данный момент.

4b9b3361

Ответ 1

В этом нет ничего плохого. Компилятор по существу делает автоматически то, что вы описали как свою альтернативу. Он создает класс для хранения захваченных переменных (test, s1 и s2) и передает экземпляр делегата в лямбда, который превращается в метод в анонимный класс. Другими словами, если вы воспользовались своей альтернативой, вы в конечном итоге сотворили бы очень похожее на то, что только что сгенерировал компилятор для вас.

Ответ 2

В этом конкретном примере нет ничего плохого здесь. Состояние, в котором вы перешли в другой поток, полностью содержится, и ни один из типов не связан с проблемами присоединения потоков.

Ответ 3

Это хороший способ сделать это. Я не вижу недостатков в использовании лямбда. Это просто и чисто.

Ответ 4

То, что вы смотрите, называется закрытием. Как chuckj states, компилятор генерирует класс во время компиляции, который соответствует элементам, доступ к которым осуществляется за пределами закрытия.

Единственное, о чем вам нужно беспокоиться, - это иметь параметры ref или out. Хотя строки неизменяемы, ссылки на них (или любые переменные) не являются.

Ответ 5

Одна потенциальная проблема с шаблоном заключается в том, что очень заманчиво расширять его на нечто более общее, но менее безопасное, как это (код нуля - не ожидайте, что он будет работать):

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
    }
}