Как начать поток с параметрами в C #?
Как начать поток с параметрами в C #?
Ответы:
Ага :
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
должен иметь тип параметраobject
ParameterizedThreadStart
и ясно из текста вопроса, это, вероятно, не так.
Одна из двух перегрузок конструктора Thread принимает делегат ParameterizedThreadStart, который позволяет передать единственный параметр методу start. К сожалению, он допускает только один параметр и делает это небезопасным способом, поскольку передает его как объект. Я считаю, что гораздо проще использовать лямбда-выражение для захвата соответствующих параметров и передачи их строго типизированным способом.
Попробуйте следующее
public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
var t = new Thread(() => RealStart(param1, param2));
t.Start();
return t;
}
private static void RealStart(SomeType param1, SomeOtherType param2) {
...
}
Dim thr As New Thread(Sub() DoStuff(settings))
Вы можете использовать лямбда-выражения
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
это пока лучший ответ, который я мог найти, это быстро и легко.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Тип параметра должен быть объектом.
РЕДАКТИРОВАТЬ:
Хотя этот ответ не является правильным, я рекомендую против такого подхода. Использование лямбда-выражения намного проще для чтения и не требует приведения типов. Смотрите здесь: https://stackoverflow.com/a/1195915/52551
Parameter
?
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));
t.Start("My Parameter");
}
static void ThreadMethod(object parameter)
{
// parameter equals to "My Parameter"
}
}
Простой способ использования лямбда, как это ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
ИЛИ вы могли бы даже delegate
использовать, ThreadStart
как так ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
ИЛИ используя VS 2019 .NET 4.5+ даже чище, как это ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Использование ParametrizedThreadStart
.
Как уже упоминалось в различных ответах здесь, Thread
класс в настоящее время (4.7.2) предоставляет несколько конструкторов и Start
метод с перегрузками.
Эти соответствующие конструкторы для этого вопроса:
public Thread(ThreadStart start);
и
public Thread(ParameterizedThreadStart start);
которые либо принимают ThreadStart
делегата, либо ParameterizedThreadStart
делегата.
Соответствующие делегаты выглядят так:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Таким образом, как видно, правильный конструктор, который нужно использовать, - это тот, который принимает ParameterizedThreadStart
делегат, так что поток, соответствующий некоторому методу, соответствующему указанной сигнатуре делегата, может быть запущен потоком.
Простой пример создания экземпляра Thread
класса:
Thread thread = new Thread(new ParameterizedThreadStart(Work));
или просто
Thread thread = new Thread(Work);
Сигнатура соответствующего метода (вызываемого Work
в этом примере) выглядит следующим образом:
private void Work(object data)
{
...
}
Осталось только начать тему. Это делается с помощью либо
public void Start();
или
public void Start(object parameter);
Хотя Start()
бы запустить поток и передать в null
качестве данных в метод, Start(...)
может использоваться для передачи чего-либо в Work
метод потока.
Однако у этого подхода есть одна большая проблема: все, что передается в Work
метод, преобразуется в объект. Это означает, что в Work
методе он должен быть снова приведен к исходному типу, как в следующем примере:
public static void Main(string[] args)
{
Thread thread = new Thread(Work);
thread.Start("I've got some text");
Console.ReadLine();
}
private static void Work(object data)
{
string message = (string)data; // Wow, this is ugly
Console.WriteLine($"I, the thread write: {message}");
}
Кастинг - это то, что вы обычно не хотите делать.
Что если кто-то пропустит что-то еще, что не является строкой? Поскольку вначале это кажется невозможным (поскольку это мой метод, я знаю, что я делаю, или метод частный, как кто-то может быть в состоянии что-либо передать ему? ), Вы можете в конечном итоге получить именно этот случай по разным причинам. , Поскольку некоторые случаи могут не быть проблемой, другие - нет. В таких случаях вы, вероятно, в конечном итоге InvalidCastException
получите, который вы, вероятно, не заметите, потому что он просто завершает поток.
В качестве решения вы ожидаете получить общий ParameterizedThreadStart
делегат, например, ParameterizedThreadStart<T>
где T
будет тип данных, которые вы хотите передать в Work
метод. К сожалению что-то подобное не существует (пока?).
Однако есть предложенное решение этой проблемы. Он включает в себя создание класса, который содержит как данные, передаваемые в поток, так и метод, представляющий метод работ, например:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
При таком подходе вы начинаете поток так:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Таким образом, вы просто избегаете перебора и имеете безопасный способ предоставления данных потоку ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
невозможно и так далее)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. В любом случае, вместо того, чтобы использовать ваш метод многопоточности, я нашел его более удобным Tasks<T>
, как, например tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, см. Мой ответ ниже ( stackoverflow.com/a/59777250/7586301 )
У меня была проблема в переданном параметре. Я передал целое число из цикла for в функцию и отобразил ее, но она всегда давала разные результаты. как (1,2,2,3) (1,2,3,3) (1,1,2,3) и т. д. с делегатом ParametrizedThreadStart .
этот простой код работал как шарм
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
ParameterizedThreadStart
Принимает один параметр. Вы можете использовать это для отправки одного параметра или пользовательского класса, содержащего несколько свойств.
Другой метод - поместить метод, который вы хотите запустить как член экземпляра, в класс вместе со свойствами для параметров, которые вы хотите установить. Создайте экземпляр класса, установите свойства и запустите поток, указав экземпляр и метод, и метод может получить доступ к свойствам.
Вы можете использовать делегат ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Вы можете использовать метод BackgroundWorker RunWorkerAsync и передать свое значение.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.IsBackground = true;//i can stope
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}`enter code here`
}
}
Я предлагаю использовать Task<T>
вместо Thread
; он допускает несколько параметров и работает очень хорошо.
Вот рабочий пример:
public static void Main()
{
List<Task> tasks = new List<Task>();
Console.WriteLine("Awaiting threads to finished...");
string par1 = "foo";
string par2 = "boo";
int par3 = 3;
for (int i = 0; i < 1000; i++)
{
tasks.Add(Task.Run(() => Calculate(par1, par2, par3)));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads finished!");
}
static bool Calculate1(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
// if need to lock, use this:
private static Object _locker = new Object();"
static bool Calculate2(string par1, string par2, int par3)
{
lock(_locker)
{
//...
return true;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
int x = 10;
Thread t1 =new Thread(new ParameterizedThreadStart(order1));
t1.Start(x);
Thread t2=new Thread(order2);
t2.Priority = ThreadPriority.Highest;
t2.Start();
Console.ReadKey();
}//Main
static void order1(object args)
{
int x = (int)args;
for (int i = 0; i < x; i++)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(i.ToString() + " ");
}
}
static void order2()
{
for (int i = 100; i > 0; i--)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(i.ToString() + " ");
}
}
}
}