파라미터가있는 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 = delegate {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

Thread 생성자의 오버로드 중 하나는 하나의 매개 변수를 start 메서드에 전달할 수있는 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 2009

2
이 솔루션은 표준형보다 훨씬 낫습니다. ParameterizedThreadStart
Piotr Owsiak

5
너무 간단합니다. 그냥 새로운 Thread (() =>는 foobar ()) "에있는 전화 .Start ()를 감싸
토마스 제스 퍼슨

12
멋진 VB.NET 사용자를위한 것입니다Dim thr As New Thread(Sub() DoStuff(settings))
박사. evil

3
@bavaza 나는 정적 타입 검사를 언급했다
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

이것은 이런 종류의 대표에게 익숙한 사람들에게 가장 효과적입니다. 초보자가 이해하기 어려울 수 있습니다. 그러나 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
Thread t 초기화에서 ThreadMethod를 방금 통과하면 차이점은 무엇입니까?
Joe

매개 변수 유형은 '객체'형식이어야한다 기억
쿠날 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>TWork 방법을. 불행히도 이와 같은 것이 존재하지 않습니다 (아직?).

그러나이 문제에 대한 제안 된 해결책 이 있습니다. 여기에는 스레드에 전달할 데이터와 작업자 메서드를 나타내는 다음과 같은 메서드가 모두 포함 된 클래스를 만드는 과정이 포함됩니다.

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 Thanks ;-) 솔루션이 꽤 좋아 보입니다. 그러나 유형별 정보는 여전히 객체에 박스로 표시되므로 액세스 할 수 없습니다. (예 : message.Length불가능합니다)
Markus Safar

1
바로 ... 당신은 message.GetType ()과 같은 특정 속성이 필요한 경우 캐스팅 할 수 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

전달 된 매개 변수에 문제가있었습니다. for 루프에서 함수로 정수를 전달하고 표시했지만 항상 다른 결과를 냈습니다. ParametrizedThreadStart 델리게이트가있는 (1,2,2,3) (1,2,3,3) (1,1,2,3) 등 .

이 간단한 코드는 매력으로 작동했습니다

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

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

4

그만큼 ParameterizedThreadStart 하나 개의 매개 변수를 사용합니다. 이를 사용하여 하나의 매개 변수 또는 여러 속성을 포함하는 사용자 정의 클래스를 보낼 수 있습니다.

또 다른 방법은 설정하려는 매개 변수의 속성과 함께 클래스에서 인스턴스 멤버로 시작하려는 방법을 넣는 것입니다. 클래스의 인스턴스를 만들고 속성을 설정하고 인스턴스와 메서드를 지정하여 스레드를 시작하면 메서드가 속성에 액세스 할 수 있습니다.


3

ParametrizedThreadStart 델리게이트를 사용할 수 있습니다 :

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

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.