ThreadStart dengan parameter

261

Bagaimana Anda memulai utas dengan parameter dalam C #?

JL.
sumber
Jawaban untuk pertanyaan ini sangat bervariasi antar versi runtime - apakah 3,5 jawaban baik-baik saja?
quillbreaker
4
Wow. Saya telah mengedit beberapa pertanyaan lama Anda, tetapi itu bisa berupa pekerjaan penuh waktu. Saya sudah lupa, eh, seberapa banyak Anda telah meningkat selama bertahun-tahun. :-)
John Saunders
Jika saya mengajukan pertanyaan singkat seperti itu, saya akan mendapatkan 5 skor negatif atau bahkan lebih! Meskipun pertanyaan dan jawabannya membantu saya.
Mohammad Musavi

Jawaban:

174

Yap:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
Erick
sumber
14
apakah ini sama: ThreadStart processTaskThread = delegate {ProcessTasks (databox.DataboxID); }; Thread baru (processTaskThread). Mulai ();
JL.
43
Apa itu myParamObject dan myUrl?
dialex
3
Dalam hal ini void MyParamObject(object myUrl){ //do stuff }harus memiliki tipe parameterobject
Elshan
15
-1 karena jawabannya mengasumsikan bahwa OP tahu cara menggunakan ParameterizedThreadStartdan dengan jelas dari teks pertanyaan, yang mungkin bukan itu masalahnya.
JYelton
2
Saya memiliki kesalahan ini Kesalahan CS0123 Tidak ada kelebihan untuk 'UpdateDB' cocok dengan delegasi 'ParameterizedThreadStart'
Omid Farvid
482

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) {
  ...
}
JaredPar
sumber
41
+1: Meskipun jawaban yang saat ini dipilih benar-benar benar, yang ini oleh JaredPar adalah yang lebih baik. Ini hanyalah solusi terbaik untuk sebagian besar kasus praktis.
galaktor
2
Solusi ini jauh lebih baik daripada standar
StandardizedThreadStart
5
Bagus, sangat sederhana. Hanya bungkus panggilan apa pun di "Utas baru (() => FooBar ()). Mulai ();
Thomas Jespersen
12
Luar biasa, ini untuk VB.NET guysDim thr As New Thread(Sub() DoStuff(settings))
dr. evil
3
@ bavaza Saya baru saja merujuk pada pemeriksaan tipe statis
JaredPar
141

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.

Georgi-it
sumber
6
Solusi terbaik untuk kasus sederhana IMO
Dunc
1
apa itu =>? dan di mana saya dapat menemukan informasi lebih lanjut tentang sintaks?
Nick
2
Ini adalah ungkapan lambda, beberapa info dapat ditemukan di alamat ini: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it
1
Ini berhasil untuk saya. Saya mencoba ParameterizedThreadStart dan variasi tetapi tidak memiliki sukacita. Saya menggunakan .NET Framework 4 di aplikasi konsol yang seharusnya sederhana.
Daniel Hollinrake
Ini bekerja paling baik untuk orang-orang yang terbiasa dengan delegasi semacam ini. Mungkin sulit bagi pemula untuk mengerti. Ini bersih untuk standar C #. Jawaban yang diterima tidak bekerja untuk saya dan saya tidak punya waktu untuk mencari tahu mengapa.
Bitterblue
37
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

Spencer Ruport
sumber
Mengapa Anda membantu dengan kode yang tidak dikompilasi;) Parameter?
Sebastian Xawery Wiśniowiecki
32
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"
    }
}
huseyint
sumber
3
Ini memberi saya "Tidak ada kelebihan untuk delegasi 'DoWork' pertandingan 'Sistem .Threading.ParameterizedThreadStart'
anon58192932
1
Apa perbedaannya jika Anda baru saja melewati ThreadMethod di inisialisasi Thread t?
Joe
Ingat, tipe parameter harus dari Tipe 'Objek'
Kunal Uppal
28

Cara sederhana menggunakan lambda seperti itu ..

Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();

ATAU Anda bahkan dapat delegatemenggunakan ThreadStartseperti ...

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..
}
Tuan Mick
sumber
6

Seperti telah disebutkan dalam berbagai jawaban di sini, Threadkelas saat ini (4.7.2) menyediakan beberapa konstruktor dan Startmetode dengan kelebihan.

Konstruktor yang relevan untuk pertanyaan ini adalah:

public Thread(ThreadStart start);

dan

public Thread(ParameterizedThreadStart start);

baik yang mengambil ThreadStartdelegasi atau ParameterizedThreadStartdelegasi.

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 ParameterizedThreadStartdelegasi sehingga beberapa metode sesuai dengan tanda tangan yang ditentukan dari delegasi dapat dimulai oleh utas.

Contoh sederhana untuk instanciating Threadkelas akan menjadi

Thread thread = new Thread(new ParameterizedThreadStart(Work));

atau hanya

Thread thread = new Thread(Work);

Tanda tangan dari metode yang sesuai (disebut Workdalam 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 nullsebagai data ke metode, Start(...)dapat digunakan untuk melewatkan apa pun ke dalam Workmetode utas.

Namun ada satu masalah besar dengan pendekatan ini: Segala sesuatu yang dilewatkan ke dalam Workmetode dilemparkan ke objek. Itu berarti dalam Workmetode 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 ParameterizedThreadStartdelegasi generik seperti di ParameterizedThreadStart<T>mana Takan menjadi tipe data yang ingin Anda sampaikan ke dalam Workmetode. 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 ;-)

Markus Safar
sumber
Wow, downvote tanpa komentar ... Entah jawaban saya seburuk para pemain atau pembaca tidak mengerti apa yang saya coba tunjukkan di sini ;-)
Markus Safar
1
Saya menemukan solusi Anda sangat mencerahkan, selamat. Hanya ingin menambahkan bahwa saya sudah menguji di Net.Core yang berikut dan bekerja tanpa harus pelemparan kejujuran! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford
@ PaulEfford Terima kasih ;-) Solusi Anda sepertinya cukup bagus. Tetapi Anda tidak mendapatkan akses untuk mengetik informasi spesifik karena masih akan dikotakkan ke suatu objek, bukan? (mis. message.Lengthtidak mungkin dan sebagainya)
Markus Safar
1
kanan ... Anda bisa mengirim pesan. Dapatkan Tipe () dan berikan jika Anda ingin properti apa pun yang diinginkan 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 )
Paul Efford
5

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; 
}
pengguna3805007
sumber
4

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.

Guffa
sumber
3

Anda bisa menggunakan delegasi ParametrizedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
CMS
sumber
1
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`
    }
}
Mohammed Hassen Ismaile
sumber
0

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;
        }
    }
Paul Efford
sumber
-2
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() + " ");
            }
        }
    }
}
Mohammed Hassen Ismaile
sumber
Multi threading dengan C # Threads memungkinkan Anda untuk mengembangkan sinkronisasi aplikasi yang lebih efisien melalui memori bersama.
Mohammed Hassen Ismaile