Як запустити потік з параметрами в C #?
Як запустити потік з параметрами в C #?
Відповіді:
Так:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
повинен бути тип параметраobject
ParameterizedThreadStart
і чітко з тексту запитання, це, мабуть, не так.
Одне з 2 перевантажень конструктора Thread використовує делегат ParameterizedThreadStart, який дозволяє передавати один параметр методу запуску. На жаль, він допускає лише один параметр і робить це небезпечно, оскільки передає його як об'єкт. Мені здається, що набагато простіше використовувати лямбда-вираз для збору відповідних параметрів та передачі їх у сильно набраному вигляді.
Спробуйте наступне
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() + " ");
}
}
}
}