ThreadStart với các tham số


261

Làm thế nào để bạn bắt đầu một chủ đề với các tham số trong C #?


Câu trả lời cho câu hỏi này rất khác nhau giữa các phiên bản của thời gian chạy - câu trả lời có ổn không?
quillbreaker

4
Ồ Tôi đã chỉnh sửa một số câu hỏi cũ của bạn, nhưng nó có thể là một công việc toàn thời gian. Tôi đã quên mất, uh, bạn đã tiến bộ bao nhiêu trong những năm qua. :-)
John Saunders

Nếu tôi hỏi một câu hỏi ngắn gọn như vậy, tôi sẽ nhận được 5 điểm âm hoặc thậm chí nhiều hơn! Mặc dù câu hỏi và câu trả lời đã giúp tôi.
Mohammad Musavi

Câu trả lời:


174

Vâng :

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

14
là như vậy: ThreadStart processTaskThread = ủy nhiệm {ProcessT task (databox.DataboxID); }; Chủ đề mới (processTaskThread) .Start ();
JL.

43
MyParamObject và myUrl là gì?
dialex

3
Trong trường hợp này void MyParamObject(object myUrl){ //do stuff }nên có loại tham sốobject
El Sơn

15
-1 vì câu trả lời giả định rằng OP biết cách sử dụng ParameterizedThreadStartvà rõ ràng từ văn bản câu hỏi, đó có lẽ không phải là trường hợp.
JYelton 6/2/2015

2
Tôi có lỗi này Lỗi CS0123 Không quá tải cho 'UpdateDB' khớp với đại biểu 'ParameterizedThreadStart'
Omid Farvid

482

Một trong 2 tình trạng quá tải của hàm tạo Thread đưa ra một đại biểu ParameterizedThreadStart cho phép bạn truyền một tham số duy nhất cho phương thức start. Thật không may, mặc dù nó chỉ cho phép một tham số duy nhất và nó làm như vậy theo cách không an toàn vì nó chuyển nó dưới dạng đối tượng. Tôi thấy việc sử dụng biểu thức lambda dễ dàng hơn nhiều để nắm bắt các tham số có liên quan và chuyển chúng theo kiểu được gõ mạnh.

Hãy thử như sau

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: Mặc dù câu trả lời hiện được chọn là hoàn toàn chính xác, nhưng câu trả lời này của JaredPar là câu trả lời tốt hơn. Nó đơn giản là giải pháp tốt nhất cho hầu hết các trường hợp thực tế.
galaktor

2
Giải pháp này tốt hơn nhiều so với ParameterizedThreadStart
Piotr Owsiak

5
Đẹp quá đơn giản. Chỉ cần bọc bất kỳ cuộc gọi nào trong "Chủ đề mới (() => FooBar ()) .Start ();
Thomas Jespersen

12
Tuyệt vời, đây là dành cho những người VB.NETDim thr As New Thread(Sub() DoStuff(settings))
dr. ác

3
@bavaza Tôi chỉ đề cập đến việc kiểm tra kiểu tĩnh
JaredPar

141

Bạn có thể sử dụng biểu thức lambda

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

đây là câu trả lời tốt nhất tôi có thể tìm thấy, nó nhanh và dễ dàng.


6
Giải pháp tốt nhất cho các trường hợp đơn giản IMO
Dunc

1
đó là gì =>? và tôi có thể tìm thêm thông tin về cú pháp ở đâu?
Nick

2
Đây là một biểu thức lambda, một số thông tin có thể được tìm thấy trên các địa chỉ này: msdn.microsoft.com/en-us/l Library / vstudio / bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
Điều này làm việc cho tôi. Tôi đã thử ParameterizedThreadStart và các biến thể của nó nhưng không có niềm vui. Tôi đã sử dụng .NET Framework 4 trong một ứng dụng giao diện điều khiển đơn giản.
Daniel Hollinrake 17/03/2016

Điều này hoạt động tốt nhất cho những người đã quen với các loại đại biểu. Có thể khó khăn cho người mới bắt đầu hiểu. Điều này là sạch cho các tiêu chuẩn C # mặc dù. Câu trả lời được chấp nhận không có tác dụng với tôi và tôi không có thời gian để tìm hiểu lý do tại sao.
Bitterblue

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

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

Loại tham số phải là một đối tượng.

BIÊN TẬP:

Trong khi câu trả lời này không chính xác, tôi khuyên bạn nên chống lại phương pháp này. Sử dụng biểu thức lambda dễ đọc hơn nhiều và không yêu cầu truyền kiểu. Xem tại đây: https://stackoverflow.com/a/1195915/52551


Tại sao bạn lại giúp với một mã không biên dịch;) 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
Điều này mang lại cho tôi "Không quá tải cho 'DoWork' phù hợp với đại biểu 'System.Threading.ParameterizedThreadStart'
anon58192932

1
Điều gì sẽ là sự khác biệt nếu bạn vừa vượt qua ThreadMethod trong quá trình khởi tạo Thread t?
Joe

Hãy nhớ rằng, loại tham số phải là Loại 'Đối tượng'
Kunal Uppal

28

Cách đơn giản sử dụng lambda như vậy ..

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

HOẶC bạn thậm chí có thể delegatesử dụng ThreadStartnhư vậy ...

ThreadStart ts = delegate
{
     bool moreWork = DoWork("param1", "param2", "param3");
     if (moreWork) 
     {
          DoMoreWork("param4", "param5");
     }
};
new Thread(ts).Start();

HOẶC sử dụng VS 2019 .NET 4.5+ thậm chí còn sạch hơn như vậy ..

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}



6

Như đã được đề cập trong các câu trả lời khác nhau ở đây, Threadlớp hiện tại (4.7.2) cung cấp một số hàm tạo và một Startphương thức với tình trạng quá tải.

Những nhà xây dựng có liên quan cho câu hỏi này là:

public Thread(ThreadStart start);

public Thread(ParameterizedThreadStart start);

trong đó có một ThreadStartđại biểu hoặc một ParameterizedThreadStartđại biểu.

Các đại biểu tương ứng trông như thế này:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

Vì vậy, như có thể thấy, hàm tạo chính xác để sử dụng dường như là hàm lấy một ParameterizedThreadStartđại biểu để một số phương thức phù hợp với chữ ký được chỉ định của đại biểu có thể được bắt đầu bởi luồng.

Một ví dụ đơn giản để kích hoạt Threadlớp học sẽ là

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

hoặc chỉ

Thread thread = new Thread(Work);

Chữ ký của phương thức tương ứng (được gọi Worktrong ví dụ này) trông như thế này:

private void Work(object data)
{
   ...
}

Những gì còn lại là bắt đầu chuỗi. Điều này được thực hiện bằng cách sử dụng một trong hai

public void Start();

hoặc là

public void Start(object parameter);

Trong khi Start()sẽ bắt đầu luồng và truyền nulldưới dạng dữ liệu cho phương thức, Start(...)có thể được sử dụng để truyền bất cứ thứ gì vào Workphương thức của luồng.

Tuy nhiên, có một vấn đề lớn với cách tiếp cận này: Mọi thứ được truyền vào Workphương thức đều được đưa vào một đối tượng. Điều đó có nghĩa là trong Workphương thức nó phải được chuyển sang loại ban đầu như trong ví dụ sau:

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



Đúc là điều bạn thường không muốn làm.

Điều gì xảy ra nếu ai đó vượt qua một thứ khác không phải là một chuỗi? Vì điều này ban đầu dường như không thể (vì đó là phương pháp của tôi, tôi biết tôi làm gì hoặc Phương pháp này là riêng tư, làm thế nào để ai đó có thể chuyển bất cứ điều gì cho nó? ) Bạn có thể kết thúc chính xác với trường hợp đó vì nhiều lý do . Vì một số trường hợp có thể không phải là một vấn đề, những người khác là. Trong những trường hợp như vậy, bạn có thể sẽ kết thúc với một InvalidCastExceptioncái mà bạn có thể sẽ không nhận thấy bởi vì nó chỉ đơn giản là chấm dứt chuỗi.

Là một giải pháp mà bạn mong đợi để có được một ParameterizedThreadStartđại biểu chung giống như ParameterizedThreadStart<T>nơi Tsẽ là loại dữ liệu bạn muốn truyền vào Workphương thức. Thật không may, một cái gì đó như thế này không tồn tại (chưa?).

Tuy nhiên, có một giải pháp được đề xuất cho vấn đề này. Nó liên quan đến việc tạo một lớp chứa cả hai, dữ liệu được truyền đến luồng cũng như phương thức đại diện cho phương thức worker như thế này:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

Với phương pháp này, bạn sẽ bắt đầu chuỗi như thế này:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

Vì vậy, theo cách này, bạn chỉ cần tránh truyền xung quanh và có một cách an toàn để cung cấp dữ liệu cho một chuỗi ;-)


Wow, một downvote không có bình luận ... Hoặc câu trả lời của tôi cũng tệ như diễn viên hoặc người đọc không hiểu những gì tôi đã cố gắng chỉ ra ở đây ;-)
Markus Safar

1
Tôi thấy giải pháp của bạn rất giác ngộ, xin chúc mừng. Chỉ muốn thêm rằng tôi đã thử nghiệm trên Net. Đã làm như sau và đã làm việc mà không cần phải khám phá diễn viên! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford

@PaulEfford Cảm ơn ;-) Giải pháp của bạn có vẻ khá hay. Nhưng bạn không có quyền truy cập để nhập thông tin cụ thể vì nó vẫn sẽ được đóng hộp cho một đối tượng, phải không? (ví dụ message.Lengthlà không thể và v.v.)
Markus Safar

1
đúng ... bạn có thể nhắn tin.GetType () và bỏ qua nếu yêu cầu bất kỳ thuộc tính cụ thể nào như if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. Dù sao, thay vì sử dụng phương pháp phân luồng của bạn, tôi thấy thoải mái hơn khi sử dụng Tasks<T>, ví dụ như tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))xem câu trả lời của tôi bên dưới ( stackoverflow.com/a/59777250/7586602 )
Paul Efford

5

Tôi đã có vấn đề trong các tham số thông qua. Tôi đã truyền số nguyên từ một vòng lặp for cho hàm và hiển thị nó, nhưng nó luôn cho ra các kết quả khác nhau. như (1,2,2,3) (1,2,3,3) (1,1,2,3), v.v ... với đại biểu ParametrienedThreadStart .

mã đơn giản này làm việc như một nét duyên dáng

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

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

4

Các ParameterizedThreadStarttham số mất một. Bạn có thể sử dụng nó để gửi một tham số hoặc một lớp tùy chỉnh có chứa một số thuộc tính.

Một phương thức khác là đặt phương thức mà bạn muốn bắt đầu như một thành viên thể hiện trong một lớp cùng với các thuộc tính cho các tham số mà bạn muốn đặt. Tạo một thể hiện của lớp, đặt các thuộc tính và bắt đầu luồng chỉ định thể hiện và phương thức và phương thức có thể truy cập các thuộc tính.


3

Bạn có thể sử dụng một đại biểu ParametrienedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);


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

Tôi đề nghị sử dụng Task<T>thay vì Thread; nó cho phép nhiều tham số và thực thi tốt.

Dưới đây là một ví dụ hoạt động:

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

Đa luồng với Chủ đề C # cho phép bạn phát triển các ứng dụng đồng bộ hóa hiệu quả hơn thông qua bộ nhớ dùng chung.
Mohammed Hassen Ismaile
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.