ThreadStart พร้อมพารามิเตอร์


261

คุณเริ่มเธรดด้วยพารามิเตอร์ใน C # ได้อย่างไร


คำตอบสำหรับคำถามนี้แตกต่างกันอย่างมากในเวอร์ชันของรันไทม์ - เป็น 3.5 คำตอบที่ดี?
quillbreaker

4
ว้าว. ฉันแก้ไขคำถามเก่า ๆ ของคุณแล้ว แต่อาจเป็นงานเต็มเวลา ฉันลืมไปแล้วเอ่อคุณได้พัฒนาไปมากแค่ไหนในช่วงหลายปีที่ผ่านมา :-)
John Saunders

ถ้าฉันถามคำถามสั้น ๆ ฉันจะได้คะแนนลบ 5 คะแนนหรือมากกว่านั้น! แม้ว่าคำถามและคำตอบช่วยฉันได้
Mohammad Musavi

คำตอบ:


174

อ๋อ

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);

14
เหมือนกัน: ThreadStart processTaskThread = ผู้รับมอบสิทธิ์ {ProcessTasks (databox.DataboxID); }; กระทู้ใหม่ (processTaskThread) .Start ();
JL

43
myParamObject และ myUrl คืออะไร
dialex

3
ในกรณีนี้void MyParamObject(object myUrl){ //do stuff }ควรมีประเภทพารามิเตอร์object
Elshan

15
-1 เนื่องจากคำตอบสมมติว่า OP รู้วิธีใช้ParameterizedThreadStartและชัดเจนจากข้อความคำถามนั่นอาจไม่ใช่กรณี
JYelton

2
ฉันมีข้อผิดพลาดนี้ CS0123 ไม่มีข้อผิดพลาดเกินพิกัดสำหรับ 'UpdateDB' ที่ตรงกัน 'ParameterizedThreadStart'
Omid Farvid

482

หนึ่งใน 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) {
  ...
}

41
+1: แม้ว่าคำตอบที่เลือกไว้ในปัจจุบันจะถูกต้องทั้งหมด แต่ JaredPar นี้เป็นคำตอบที่ดีกว่า มันเป็นทางออกที่ดีที่สุดสำหรับกรณีที่ใช้งานได้จริง
galaktor

2
การแก้ปัญหานี้ดีกว่ามากแล้ว standrard ParameterizedThreadStart
Piotr Owsiak

5
ง่ายมาก เพียงแค่วางสายใน "new Thread (() => FooBar ()) .Start ();
Thomas Jespersen

12
ยอดเยี่ยมนี้สำหรับ VB.NET พวกDim thr As New Thread(Sub() DoStuff(settings))
dr ชั่วร้าย

3
@ บาวาซาฉันหมายถึงการตรวจสอบประเภทคงที่
JaredPar

141

คุณสามารถใช้แลมบ์ดานิพจน์

private void MyMethod(string param1,int param2)
{
  //do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();

นี่คือคำตอบที่ดีที่สุดที่ฉันพบได้มันเร็วและง่าย


6
ทางออกที่ดีที่สุดสำหรับกรณีง่าย IMO
Dunc

1
นั่นคืออะไร> และฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับไวยากรณ์ได้ที่ไหน
Nick

2
นี่คือนิพจน์แลมบ์ดาข้อมูลบางอย่างสามารถหาได้จากที่อยู่เหล่านี้: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
สิ่งนี้ใช้ได้สำหรับฉัน ฉันลองใช้ ParameterizedThreadStart และความหลากหลายของมัน แต่ก็ไม่มีความสุข ฉันใช้. NET Framework 4 ในแอปพลิเคชั่นคอนโซลอย่างง่าย
Daniel Hollinrake

วิธีนี้ใช้ได้ผลดีที่สุดสำหรับผู้ที่คุ้นเคยกับผู้ได้รับมอบหมายประเภทนี้ อาจเป็นเรื่องยากสำหรับผู้เริ่มต้นถึง udnerstand สิ่งนี้สะอาดสำหรับมาตรฐาน C # คำตอบที่ได้รับการยอมรับใช้ไม่ได้สำหรับฉันและฉันไม่มีเวลาที่จะหาสาเหตุ
Bitterblue

37
Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param)
{
    string Parameter = (string)param;
}

ประเภทพารามิเตอร์จะต้องเป็นวัตถุ

แก้ไข:

ในขณะที่คำตอบนี้ไม่ถูกต้องฉันขอแนะนำกับวิธีนี้ การใช้แลมบ์ดานิพจน์นั้นง่ายต่อการอ่านและไม่ต้องใช้การพิมพ์แบบหล่อ ดูที่นี่: https://stackoverflow.com/a/1195915/52551


ทำไมคุณถึงช่วยด้วยรหัสที่ไม่ได้รวบรวม;) 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"
    }
}

3
นี่คือการให้ฉัน "ไม่เกินพิกัดสำหรับ 'DoWork' จับคู่ตัวแทน 'System.Threading.ParameterizedThreadStart'
anon58192932

1
อะไรจะแตกต่างกันถ้าคุณเพิ่งผ่าน ThreadMethod ในการเริ่มต้น Thread t?
โจ

จำไว้ว่าประเภทพารามิเตอร์จะต้องเป็น 'วัตถุ' ประเภท
Kunal Uppal

28

วิธีง่ายๆในการใช้แลมบ์ดา ..

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..
}



6

ดังที่ได้กล่าวไปแล้วในคำตอบต่าง ๆ ที่นี่ใน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();

ดังนั้นด้วยวิธีนี้คุณหลีกเลี่ยงการแคสต์และมีวิธีที่ปลอดภัยในการให้ข้อมูลกับเธรด ;-)


ว้าว downvote โดยไม่ต้องแสดงความคิดเห็น ... ทั้งคำตอบของฉันไม่ดีเท่านักแสดงหรือผู้อ่านไม่เข้าใจสิ่งที่ฉันพยายามชี้ไปที่นี่ ;-)
Markus Safar

1
ฉันพบทางออกของคุณสว่างไสวมากแสดงความยินดี แค่อยากจะเพิ่มว่าฉันได้ทดสอบแล้วใน Net.Core ต่อไปนี้และทำงานได้โดยไม่ต้องร่ายเวทย์มนตร์! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford

@ PaulEfford ขอบคุณ ;-) โซลูชันของคุณดูน่ารักดี แต่คุณไม่ได้รับอนุญาตให้พิมพ์ข้อมูลเฉพาะเพราะมันจะยังคงอยู่ในกล่องของวัตถุใช่ไหม (เช่นmessage.Lengthเป็นไปไม่ได้และอื่น ๆ )
Markus Safar

1
ถูกต้อง ... คุณสามารถ message.GetType () และโยนถ้า requiered คุณสมบัติที่เฉพาะเจาะจงใด ๆ 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 )
Paul Efford

5

ฉันมีปัญหาในพารามิเตอร์ที่ส่งผ่าน ฉันส่งจำนวนเต็มจาก 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; 
}

4

ParameterizedThreadStartเวลาหนึ่งพารามิเตอร์ คุณสามารถใช้เพื่อส่งหนึ่งพารามิเตอร์หรือคลาสที่กำหนดเองที่มีคุณสมบัติหลายอย่าง

วิธีอื่นคือการวางวิธีที่คุณต้องการเริ่มต้นเป็นสมาชิกอินสแตนซ์ในคลาสพร้อมกับคุณสมบัติสำหรับพารามิเตอร์ที่คุณต้องการตั้งค่า สร้างอินสแตนซ์ของคลาสตั้งค่าคุณสมบัติและเริ่มเธรดที่ระบุอินสแตนซ์และวิธีการและวิธีการสามารถเข้าถึงคุณสมบัติ




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`
    }
}

0

ผมเสนอใช้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;
        }
    }

-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() + " ");
            }
        }
    }
}

มัลติเธรดกับ C # เธรดช่วยให้คุณสามารถพัฒนาแอปพลิเคชั่นที่มีประสิทธิภาพมากขึ้นในการซิงโครไนซ์ผ่านหน่วยความจำที่แชร์
Mohammed Hassen Ismaile
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.