Thread에서 ThreadStart 메소드에 매개 변수를 전달하는 방법은 무엇입니까?


291

Thread.ThreadStart()C #에서 메서드에 매개 변수를 전달하는 방법은 무엇입니까?

'다운로드'라는 메소드가 있다고 가정하십시오.

public void download(string filename)
{
    // download code
}

이제 메인 메소드에 하나의 스레드를 만들었습니다.

Thread thread = new Thread(new ThreadStart(download(filename));

오류 메소드 유형이 예상됩니다.

매개 변수가 ThreadStart있는 대상 메소드로 매개 변수를 전달하는 방법은 무엇입니까?


2
Jon Skeet이 작성한 기사를 확인하십시오 . 매개 변수 섹션은 다음 페이지에 있지만 기사 전체를 잘 읽어보십시오.
codingbadger

답변:


696

가장 간단한 것은

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

이것의 장점 ParameterizedThreadStart은 여러 매개 변수를 전달할 수 있으며 object항상 캐스팅하지 않아도 컴파일 타임을 확인할 수 있다는 것입니다.


15
주제 외에 죄송하지만 '()'연산자의 의미는 무엇입니까? 때때로 확인하지만 확인할 시간이 없습니다.
ŁukaszW.pl

24
인수가없는 람다 식입니다.
Noldorin

31
@ ŁukaszW.pl-Noldorin이 말한 것; C # 2.0에서 p는 대안적인 구조입니다 (이 예제의 경우)new Thread(delegate() { download(filename); });
Marc Gravell

7
아니다 @Tymek 매우 정확한; 캡처 된 모든 변수는 완전한 어휘 폐쇄 로 처리되며 , 구현 세부 사항은 컴파일러 생성 클래스에서 필드로 구현됩니다. 또한 클로저 범위는 선언 범위로 정의됩니다. "참조로 전달"및 "참조 유형"은 잘 정의되어
있으며이

5
@MarcGravell-맞습니다. 내가 말한 것은 스레드가 시작되기 전에 'filename'이 변경되면 새 값이 사용된다는 것입니다. 나는 그것의 역학에 대해 뻔뻔스러워해서는 안되며 참조에 대해 이야기해서는 안됩니다.
tymtam

36

이 예를보십시오 :

public void RunWorker()
{
    Thread newThread = new Thread(WorkerMethod);
    newThread.Start(new Parameter());
}

public void WorkerMethod(object parameterObj)
{
    var parameter = (Parameter)parameterObj;
    // do your job!
}

먼저 대리자를 작업자 메서드에 전달하여 스레드를 만든 다음 개체를 매개 변수로 사용하는 Thread.Start 메서드로 시작합니다.

따라서 귀하의 경우 다음과 같이 사용해야합니다.

    Thread thread = new Thread(download);
    thread.Start(filename);

그러나 '다운로드'방법 은 매개 변수로 문자열이 아닌 객체 를 사용해야 합니다 . 메소드 본문에서 문자열로 캐스트 할 수 있습니다.


25

ParameterizedThreadStart매개 변수 를 사용하는 스레드 메서드에 대리자 를 사용하려고합니다 . (또는 실제로는 아무것도 없으며 Thread생성자가 추론 하도록하십시오 .)

사용법 예 :

var thread = new Thread(new ParameterizedThreadStart(download));
//var thread = new Thread(download); // equivalent

thread.Start(filename)

7

당신은 또한 delegate좋아할 수 있습니다 ...

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


3

스레드 함수 (다운로드) 및 필요한 매개 변수 (파일 이름)를 클래스에 캡슐화하고 ThreadStart 대리자를 사용하여 스레드 함수를 실행할 수 있습니다.

public class Download
{
    string _filename;

    Download(string filename)
    {
       _filename = filename;
    }

    public void download(string filename)
    {
       //download code
    }
}

Download = new Download(filename);
Thread thread = new Thread(new ThreadStart(Download.download);

나는이 접근법을 훨씬 더 좋아한다. 람다 표현 접근법이 항상 올바른 매개 변수를 추적하는 것은 아니라는 것을 알았다
meanbunny

3

File이라는 다른 클래스를 사용하는 것이 좋습니다.

public class File
{
   private string filename;

   public File(string filename)
   {
      this.filename= filename;
   }

   public void download()
   {
       // download code using filename
   }
}

스레드 생성 코드에서 새 파일을 인스턴스화합니다.

string filename = "my_file_name";

myFile = new File(filename);

ThreadStart threadDelegate = new ThreadStart(myFile.download);

Thread newThread = new Thread(threadDelegate);

0

이건 어때 : (혹은 이런 식으로 사용해도 되나요?)

var test = "Hello";
new Thread(new ThreadStart(() =>
{
    try
    {
        //Staff to do
        Console.WriteLine(test);
    }
    catch (Exception ex)
    {
        throw;
    }
})).Start();

-1

귀하의 질문에 따르면 ...

C #에서 Thread.ThreadStart () 메서드에 매개 변수를 전달하는 방법은 무엇입니까?

... 그리고 오류가 발생하면 코드를 수정해야합니다.

Thread thread = new Thread(new ThreadStart(download(filename));

Thread thread = new Thread(new ThreadStart(download));
thread.Start(filename);



그러나 질문은 처음에 보이는 것처럼 더 복잡합니다.

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();

따라서이 방법으로 캐스팅을 피하고 스레드에 데이터를 제공하는 안전한 형식의 방법을 사용하십시오.


-2

여기 완벽한 방법이 있습니다 ...

private void func_trd(String sender)
{

    try
    {
        imgh.LoadImages_R_Randomiz(this, "01", groupBox, randomizerB.Value); // normal code

        ThreadStart ts = delegate
        {
            ExecuteInForeground(sender);
        };

        Thread nt = new Thread(ts);
        nt.IsBackground = true;

        nt.Start();

    }
    catch (Exception)
    {

    }
}

private void ExecuteInForeground(string name)
{
     //whatever ur function
    MessageBox.Show(name);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.