Bagaimana Anda memulai utas dengan parameter dalam C #?
Bagaimana Anda memulai utas dengan parameter dalam C #?
Jawaban:
Yap:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
harus memiliki tipe parameterobject
ParameterizedThreadStart
dan dengan jelas dari teks pertanyaan, yang mungkin bukan itu masalahnya.
Salah satu dari 2 kelebihan konstruktor Thread mengambil delegasi ParameterizedThreadStart yang memungkinkan Anda untuk melewatkan parameter tunggal ke metode mulai. Sayangnya meskipun hanya memungkinkan untuk satu parameter dan melakukannya dengan cara yang tidak aman karena dilewatkan sebagai objek. Saya menemukan jauh lebih mudah untuk menggunakan ekspresi lambda untuk menangkap parameter yang relevan dan meneruskannya dengan cara yang sangat diketik.
Coba yang berikut ini
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))
Anda dapat menggunakan ekspresi lambda
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
sejauh ini jawaban terbaik yang bisa saya temukan, cepat dan mudah.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Tipe parameter harus berupa objek.
EDIT:
Meskipun jawaban ini tidak salah, saya merekomendasikan pendekatan ini. Menggunakan ekspresi lambda jauh lebih mudah dibaca dan tidak memerlukan casting tipe. Lihat di sini: 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"
}
}
Cara sederhana menggunakan lambda seperti itu ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
ATAU Anda bahkan dapat delegate
menggunakan ThreadStart
seperti ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
ATAU menggunakan VS 2019. NET 4.5+ lebih bersih seperti itu ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Gunakan ParametrizedThreadStart
.
Seperti telah disebutkan dalam berbagai jawaban di sini, Thread
kelas saat ini (4.7.2) menyediakan beberapa konstruktor dan Start
metode dengan kelebihan.
Konstruktor yang relevan untuk pertanyaan ini adalah:
public Thread(ThreadStart start);
dan
public Thread(ParameterizedThreadStart start);
baik yang mengambil ThreadStart
delegasi atau ParameterizedThreadStart
delegasi.
Delegasi yang sesuai terlihat seperti ini:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Jadi seperti yang dapat dilihat, konstruktor yang benar untuk digunakan tampaknya adalah orang yang mengambil ParameterizedThreadStart
delegasi sehingga beberapa metode sesuai dengan tanda tangan yang ditentukan dari delegasi dapat dimulai oleh utas.
Contoh sederhana untuk instanciating Thread
kelas akan menjadi
Thread thread = new Thread(new ParameterizedThreadStart(Work));
atau hanya
Thread thread = new Thread(Work);
Tanda tangan dari metode yang sesuai (disebut Work
dalam contoh ini) terlihat seperti ini:
private void Work(object data)
{
...
}
Yang tersisa adalah memulai utas. Ini dilakukan dengan menggunakan keduanya
public void Start();
atau
public void Start(object parameter);
Sementara Start()
akan memulai utas dan meneruskan null
sebagai data ke metode, Start(...)
dapat digunakan untuk melewatkan apa pun ke dalam Work
metode utas.
Namun ada satu masalah besar dengan pendekatan ini: Segala sesuatu yang dilewatkan ke dalam Work
metode dilemparkan ke objek. Itu berarti dalam Work
metode itu harus dilemparkan ke tipe asli lagi seperti pada contoh berikut:
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}");
}
Casting adalah sesuatu yang biasanya tidak ingin Anda lakukan.
Bagaimana jika seseorang melewati sesuatu yang bukan string? Karena ini kelihatannya tidak mungkin pada awalnya (karena ini adalah metode saya, saya tahu apa yang saya lakukan atau metode ini bersifat pribadi, bagaimana mungkin seseorang bisa memberikan sesuatu padanya? ) Anda mungkin berakhir dengan kasus seperti itu karena berbagai alasan . Karena beberapa kasus mungkin tidak menjadi masalah, yang lain juga. Dalam kasus seperti itu Anda mungkin akan berakhir denganInvalidCastException
yang Anda mungkin tidak akan perhatikan karena itu hanya mengakhiri utas.
Sebagai solusi Anda akan mengharapkan untuk mendapatkan ParameterizedThreadStart
delegasi generik seperti di ParameterizedThreadStart<T>
mana T
akan menjadi tipe data yang ingin Anda sampaikan ke dalam Work
metode. Sayangnya sesuatu seperti ini belum ada (belum?).
Namun ada solusi yang disarankan untuk masalah ini. Ini melibatkan pembuatan kelas yang berisi keduanya, data yang akan diteruskan ke utas serta metode yang mewakili metode pekerja seperti ini:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Dengan pendekatan ini Anda akan memulai utas seperti ini:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Jadi dengan cara ini Anda cukup menghindari casting dan memiliki cara yang aman untuk memberikan data ke utas ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
tidak mungkin dan sebagainya)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. Bagaimanapun, alih-alih menggunakan metode threading Anda, saya menemukan sedikit lebih nyaman untuk digunakan Tasks<T>
, seperti misalnya tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, lihat jawaban saya di bawah ( stackoverflow.com/a/59777250/7586301 )
Saya mengalami masalah pada parameter yang diteruskan. Saya melewati bilangan bulat dari for loop ke fungsi dan menampilkannya, tetapi selalu memberikan hasil yang berbeda. seperti (1,2,2,3) (1,2,3,3) (1,1,2,3) dll dengan delegasi ParametrizedThreadStart .
kode sederhana ini berfungsi sebagai pesona
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Itu ParameterizedThreadStart
mengambil satu parameter. Anda dapat menggunakannya untuk mengirim satu parameter, atau kelas khusus yang berisi beberapa properti.
Metode lain adalah dengan meletakkan metode yang ingin Anda mulai sebagai anggota instance di kelas bersama dengan properti untuk parameter yang ingin Anda atur. Buat instance dari kelas, atur properti dan mulai utas yang menentukan instance dan metode, dan metode ini dapat mengakses properti.
Anda bisa menggunakan delegasi ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Anda dapat menggunakan metode BackgroundWorker RunWorkerAsync dan memberikan nilai Anda.
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`
}
}
Saya mengusulkan menggunakan Task<T>
bukan Thread
; itu memungkinkan beberapa parameter dan menjalankan sangat baik.
Berikut ini contoh kerjanya:
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() + " ");
}
}
}
}