C # 'da parametrelerle bir iş parçacığını nasıl başlatırsınız?
C # 'da parametrelerle bir iş parçacığını nasıl başlatırsınız?
Yanıtlar:
Evet:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
parametre tipi olmalıdırobject
ParameterizedThreadStart
soru metninin nasıl kullanılacağını bildiğini varsayar ve muhtemelen böyle değildir.
İş parçacığı yapıcısının 2 aşırı yüklenmesinden biri, başlatma yöntemine tek bir parametre iletmenize izin veren bir ParameterizedThreadStart delegesi alır. Ne yazık ki sadece tek bir parametreye izin veriyor ve bunu güvenli olmayan bir şekilde yapıyor çünkü nesne olarak geçiriyor. İlgili parametreleri yakalamak ve bunları güçlü bir şekilde yazılmış bir şekilde geçirmek için bir lambda ifadesi kullanmak çok daha kolay buluyorum.
Takip etmeyi dene
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))
Lambda ifadelerini kullanabilirsiniz
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
bu şimdiye kadar bulabildiğim en iyi cevap, hızlı ve kolay.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
Parametre tipi bir nesne olmalıdır.
DÜZENLE:
Bu cevap yanlış olmasa da bu yaklaşıma karşı öneriyorum. Bir lambda ifadesi kullanmak çok daha kolaydır ve tür dökümü gerektirmez. Buraya bakın: 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"
}
}
Lambda kullanarak böyle basit bir şekilde ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
YA hatta verebilir delegate
kullanarak ThreadStart
şöyle ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
VEYA VS 2019 .NET 4.5+ kullanarak bile daha temiz ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Kullanın ParametrizedThreadStart
.
Burada çeşitli cevaplarda daha önce de belirtildiği gibi, Thread
sınıf şu anda (4.7.2) birkaç kurucu ve Start
aşırı yük içeren bir yöntem sunmaktadır.
Bu soru için bu ilgili kurucular:
public Thread(ThreadStart start);
ve
public Thread(ParameterizedThreadStart start);
ya bir ThreadStart
delege ya da bir ParameterizedThreadStart
delege alır.
Karşılık gelen delegeler şöyle görünür:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Görülebileceği gibi, kullanılacak doğru kurucu bir ParameterizedThreadStart
temsilci alan kişi gibi görünmektedir, böylece temsilci tarafından belirtilen imzayla uyumlu bazı yöntemler iş parçacığı tarafından başlatılabilir.
Thread
Sınıfı örneklemek için basit bir örnek
Thread thread = new Thread(new ParameterizedThreadStart(Work));
ya da sadece
Thread thread = new Thread(Work);
İlgili yöntemin imzası ( Work
bu örnekte denir ) şöyle görünür:
private void Work(object data)
{
...
}
Geriye kalan, iş parçacığını başlatmaktır. Bu, aşağıdakilerden birini kullanarak yapılır:
public void Start();
veya
public void Start(object parameter);
İken Start()
açtığınızda, gerekli geçerdi null
yönteme veri olarak, Start(...)
geçmek kullanılabilir şey içine Work
iplik yöntemi.
Ancak bu yaklaşımda büyük bir sorun var: Work
Yönteme aktarılan her şey bir nesneye dökülüyor. Bu, Work
yöntem içinde, aşağıdaki örnekte olduğu gibi tekrar orijinal türe çevrilmesi gerektiği anlamına gelir :
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}");
}
Döküm genellikle yapmak istemediğiniz bir şeydir.
Birisi dize olmayan başka bir şey geçerse ne olur? Bu ilk başta mümkün görünmediği için (çünkü bu benim yöntemim, ne yaptığımı biliyorum veya yöntem özel, birisi ona herhangi bir şeyi nasıl geçebilir? ) Muhtemelen çeşitli nedenlerden dolayı tam olarak bu dava ile sonuçlanabilir . Bazı vakalar sorun yaratmayabileceğinden diğerleri. Bu gibi durumlarda muhtemelen birInvalidCastException
iş parçacığını sonlandırdığı için muhtemelen fark etmeyeceğiniz sonuç alırsınız.
Bir çözüm olarak bir jenerik olsun beklenir ParameterizedThreadStart
gibi temsilci ParameterizedThreadStart<T>
nereye T
sen geçirmek istediğiniz türde veriler olacağını Work
yöntemle. Ne yazık ki böyle bir şey henüz yok (henüz?).
Ancak , bu soruna önerilen bir çözüm vardır . İş parçacığına iletilecek verileri ve bunun gibi işçi yöntemini temsil eden yöntemi içeren bir sınıf oluşturmayı içerir:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Bu yaklaşımla iş parçacığını şöyle başlatacaksınız:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Böylece bu şekilde döküm yapmaktan kaçınır ve bir iş parçacığına veri sağlamanın tipik bir yoluna sahip olursunuz ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
mümkün değildir ve benzeri)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. Her neyse, diş açma yönteminizi kullanmak yerine, kullanımı biraz daha rahat buldum Tasks<T>
, örneğin tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, aşağıdaki cevabımı görün ( stackoverflow.com/a/59777250/7586301 )
Geçirilen parametrede sorun yaşıyordum. Bir for döngüsünden işleve tam sayı geçtim ve gösterdim, ancak her zaman farklı sonuçlar verdi. ParametrizedThreadStart delegesi ile (1,2,2,3) (1,2,3,3) (1,1,2,3) vb .
bu basit kod bir cazibe olarak çalıştı
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
ParameterizedThreadStart
Bir parametre alır. Bunu bir parametre veya birkaç özellik içeren özel bir sınıf göndermek için kullanabilirsiniz.
Başka bir yöntem, örnek olarak başlatmak istediğiniz yöntemi, ayarlamak istediğiniz parametrelerin özellikleriyle birlikte bir sınıfa yerleştirmektir. Sınıfın bir örneğini oluşturun, özellikleri ayarlayın ve örneği ve yöntemi belirten iş parçacığını başlatın; yöntem özelliklere erişebilir.
ParametrizedThreadStart delegesi kullanabilirsiniz :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
BackgroundWorker RunWorkerAsync yöntemini kullanabilir ve değerinizi iletebilirsiniz.
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`
}
}
Bunun Task<T>
yerine kullanmayı öneririm Thread
; birden fazla parametreye izin verir ve gerçekten iyi çalışır.
İşte çalışan bir örnek:
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() + " ");
}
}
}
}