Как мне вернуть значение из потока?
c#
.net
multithreading
Сэм
источник
источник
lock(value) { value = "Hello world"; }
лучше ли было бы обрабатывать запись значений нескольких потоков?value
. Но да, всегда помните, когда блокировка необходима.Это зависит от того, как вы хотите создать поток и доступную версию .NET:
.NET 2.0+:
A) Вы можете создать
Thread
объект напрямую. В этом случае вы можете использовать «закрытие» - объявить переменную и зафиксировать ее с помощью лямбда-выражения:Б) Вы можете использовать делегаты
IAsyncResult
и возвращаемое значение изEndInvoke()
метода:C) Вы можете использовать
BackgroundWorker
класс. В этом случае вы можете использовать захваченную переменную (например, сThread
объектом) или обработатьRunWorkerCompleted
событие:.NET 4.0+:
Начиная с .NET 4.0, вы можете использовать параллельную библиотеку задач и
Task
класс для запуска ваших потоков. Общий классTask<TResult>
позволяет получить возвращаемое значение изResult
свойства:.NET 4.5+:
Начиная с .NET 4.5, вы также можете использовать
async
/await
ключевые слова для непосредственного возврата значения из задачи вместо полученияResult
свойства:Примечание: метод, содержащий приведенный выше код, должен быть помечен
async
ключевым словом.По многим причинам использование параллельной библиотеки задач является предпочтительным способом работы с потоками.
источник
Я бы использовал подход BackgroundWorker и вернул бы результат в e.Result.
РЕДАКТИРОВАТЬ:
Обычно это связано с WinForms и WPF, но может использоваться любым типом приложений .NET. Вот пример кода для консольного приложения, использующего BackgroundWorker:
Вывод:
ОБНОВЛЕНИЕ 2014 ГОДА
См. Ответ @ Roger ниже.
https://stackoverflow.com/a/24916747/141172
Он указывает, что вы можете использовать Task, который возвращает a
Task<T>
, и проверятьTask<T>.Result
.источник
Поток - это не метод - обычно вы не «возвращаете» значение.
Однако, если вы пытаетесь получить значение из результатов некоторой обработки, у вас есть много вариантов, два основных из которых:
Это действительно зависит от того, как вы создаете поток и как вы хотите его использовать, а также от языка / фреймворка / инструментов, которые вы используете.
источник
Мой любимый класс, запускает любой метод в другом потоке всего с двумя строками кода.
использование
Помните, что longFunctionComplete НЕ будет выполняться в том же потоке, что и starthework.
Для методов, которые принимают параметры, вы всегда можете использовать замыкания или расширить класс.
источник
Вот простой пример использования делегата ...
В разделе Threading в C # есть потрясающая серия статей о многопоточности .
источник
Просто используйте делегированный подход.
Теперь создайте функцию Multiply, которая будет работать в другом потоке:
источник
Я столкнулся с этим потоком, когда также пытался получить возвращаемое значение метода, который выполняется в потоке. Я думал, что опубликую свое решение, которое работает.
В этом решении используется класс для хранения как метода, который будет выполняться (косвенно), так и возвращаемого значения. Класс можно использовать для любой функции и любого возвращаемого типа. Вы просто создаете экземпляр объекта, используя тип возвращаемого значения, а затем передаете функцию для вызова через лямбда (или делегат).
Реализация C # 3.0
Чтобы использовать этот код, вы можете использовать Lambda (или делегат). Вот пример использования лямбда-выражений:
Реализация VB.NET 2008
Любой, кто использует VB.NET 2008, не может использовать лямбды с методами, не возвращающими значения. Это влияет на
ThreadedMethod
класс, поэтому мы заставимExecuteMethod
вернуть значение функции. Это ничего не повредит.источник
В последней версии .NET Framework можно возвращать значение из отдельного потока с помощью Task, где свойство Result блокирует вызывающий поток, пока задача не завершится:
Подробнее см. Http://msdn.microsoft.com/en-us/library/dd537613(v=vs.110).aspx
источник
Делегаты ThreadStart в C #, используемые для запуска потоков, имеют тип возвращаемого значения void.
Если вы хотите получить «возвращаемое значение» из потока, вы должны записать в совместно используемое место (подходящим потокобезопасным способом) и читать из него, когда поток завершит выполнение.
источник
Если вы не хотите использовать BackgroundWorker, а просто используете обычный поток, вы можете запустить событие для возврата таких данных:
источник
thread1_
часть его подключения AsyncCompletedEventHandler . Если мое редактирование было ошибочным, пожалуйста, помогите мне понять, что там происходит.thread1_Thread1Completed +=
потому чтоthread1_Thread1Completed
это имя функции, поэтому вы не можете поместить его в левую часть оператора присваивания. Левая частьThread1Completed +=
используется, потому что это событие, поэтому она может отображаться слева от оператора присваивания для добавления обработчиков событий. Смотритеpublic event AsyncCompletedEventHandler Thread1Completed;
#region
раньше не мог видеть этот обработчик событий в вашем разделе. Я посмотрел. Честный! :)На самом деле потоки не имеют возвращаемых значений. Однако, если вы создаете делегат, вы можете вызывать его асинхронно с помощью
BeginInvoke
метода. Это выполнит метод в потоке пула потоков. Вы можете получить любое возвращаемое значение, например, call viaEndInvoke
.Пример:
GetAnswer
будет выполняться в потоке пула потоков, и по завершении вы можете получить ответ,EndInvoke
как показано.источник
BackgroundWorker хороша при разработке для Windows Forms.
Допустим, вы хотите пройти простой класс туда и обратно:
Я написал небольшой урок, который делает следующее:
Изнутри подпрограммы потока:
Добавление делегата может быть полезно для отправки ваших данных непосредственно в основной поток, но вам может потребоваться использовать Invoke, если некоторые элементы данных не являются потокобезопасными.
Чтобы проверить это, создайте небольшое консольное приложение и поместите его в файл Program.cs :
Вот скриншот того, что у меня получилось:
Я надеюсь, что другие поймут то, что я пытался объяснить.
Мне нравится работать с потоками и использовать делегатов. Они делают C # очень интересным.
Приложение: для кодеров VB
Я хотел увидеть, что было задействовано в написании кода выше в качестве консольного приложения VB. Преобразование включало несколько вещей, которых я не ожидал, поэтому я обновлю эту ветку здесь для тех, кто хочет знать, как использовать потоки в VB.
источник
источник
test(){ Thread.Sleep(5000); /*Highly time demanding process*/ return "Returned from test()";}
. В этом случае автономный поток не успеет присвоитьreturnValue
переменной новое значение . В крайнем случае, вы можете сохранить ссылку на потокvar standaloneThread = new Thread(()=> //...);
и после этого запустить его синхронноstandaloneThread.Start(); standaloneThread.Join();
. Но это, конечно, не лучшая практика.Простое решение - передать параметр по ссылке функции, которая выполняется в потоке, и изменить его значение в потоке.
Если вы не можете изменить функцию, которая выполняется в протекторе, вы можете обернуть ее другой функцией:
источник
Можно использовать этот код:
источник
Я не специалист по многопоточности, поэтому сделал это так:
Я создал файл настроек и
Внутри новой ветки:
Затем я беру это значение всякий раз, когда мне это нужно.
источник