คุณเริ่มเธรดด้วยพารามิเตอร์ใน C # ได้อย่างไร
คุณเริ่มเธรดด้วยพารามิเตอร์ใน C # ได้อย่างไร
คำตอบ:
อ๋อ
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
ควรมีประเภทพารามิเตอร์object
ParameterizedThreadStart
และชัดเจนจากข้อความคำถามนั่นอาจไม่ใช่กรณี
หนึ่งใน 2 โอเวอร์โหลดของตัวสร้างเธรดดำเนินการมอบหมาย 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..
}
ดังที่ได้กล่าวไปแล้วในคำตอบต่าง ๆ ที่นี่ใน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 )
ฉันมีปัญหาในพารามิเตอร์ที่ส่งผ่าน ฉันส่งจำนวนเต็มจาก a ไปยังฟังก์ชันและแสดงผล แต่ให้ผลลัพธ์ที่แตกต่างกันเสมอ กดไลค์ (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() + " ");
}
}
}
}