2012-01-06 4 views
11

두 스레드 간의 통신을 구현하는 가장 좋은 방법은 무엇입니까? 나는 난수 (클래스 송신자)를 생성하는 스레드를 하나 가지고 있고 생성 된 난수를 수신 할 다른 스레드 (클래스 수신기)를 갖고 싶습니다. 이 보낸 사람입니다 :스레딩, 두 스레드 간의 통신 C#

public class Sender 
{ 
    public int GenerateNumber(){ 


     //some code 
     return randomNumber; 
    } 
} 

Afcourse은 주요 기능에 내가 그 스레드를 시작합니다 :

static void Main(string[] args){ 

    Sender _sender=new Sender(); 
    Thread thread1=new Thread(new ThreadStart(_sender.GenerateNumber)); 

} 

나는, 당신은 자원의 일종 (리스트, 큐가 필요합니다

+0

두 스레드가 동시에 시작합니까? 수신자가 발신자를 기다리는 동안 수행하는 작업은 무엇입니까? Sender는 임의의 숫자를 생성 한 후 무엇을합니까? – cadrell0

+0

IS this is .NET 4? – Yahia

+0

주 기능에서 두 스레드를 모두 시작하고 스레드 송신기가 작동하고 3 초 동안 대기합니다. 또한 데이터를 수신 할 스레드 수신자의 인스턴스를 시작합니다 ...basiclly 쓰레드는 사용자가 누를 때마다 esc 키를 누른다. reciever ll은받은 콘솔 번호에 글을 쓴다. – Avicena00

답변

2

당신의 도움을 주셔서 감사합니다 등). 그리고이 리소스에 대한 액세스를 동기화해야합니다. 그렇지 않으면 스레드간에 데이터를 전달할 수 없습니다.

19

.NET 4를 사용하는 경우 높은 수준의 추상화를 사용하는 것이 좋습니다 (Task<TResult>). 첫 번째 스레드는 작업을 예약 할 수 있습니다 (스레드 작성을 끝내거나 기존 작업 처리 스레드에서 예약 될 수 있음). 그런 다음 상태를 확인하고 결과에 맞게 차단합니다.

원샷 작업 이상을 수행하려는 경우 생산자/소비자 대기열을 사용할 수 있습니다. 다시 .NET 4는 BlockingCollection<T>을 통해이를 지원합니다.

+1

나는 C#을 깊이 읽어야한다는 것을 알았습니다. 오늘 저녁에 시작하겠습니다 :) – Avicena00

+1

@AintMeBabe : 솔직히 말해 C#은 MSDN을 통한 작업 병렬 라이브러리에 대한 새로운 '작업 '작업을 거의 다루지 않았습니다. 블로그 게시물은 책보다 더 즉각적인 이점이 될 수 있습니다. 물론 장기적으로 당신을 낙담시키지 않을 것입니다. –

+0

생산자를 통제 할 수 없다면 어떻게 될까요? 내 컨텍스트에서 스레드 A (내 통제하에) 뭔가를 수행하고 스레드 B 이벤트를 발생시킬 때까지 기다릴 필요가; 스레드 B는 라이브러리에 의해 생성됩니다. 나는 그 사건을 경청한다. 이벤트 리스너 (스레드 B에서 실행 중)가 스레드 A에 어떻게 통지해야합니까? ManualResetEvent 이외에는 아무것도 생각할 수 없습니다. NET 4에서 더 나은 접근법이 있습니까? – Jimmy

0

당신이하고있는 모든 작업이 하나의 스레드에서 난수를 생성하는 것이라면 대신이 작업을 수행하는 스레드 안전 객체를 생성 할 것입니다.

lock(syncRoot) 
{ 
    myCurrentRandom = Generate(); 
    return myCurrentRandom; 
} 
+0

좋은 점은, 이것은 스레드 송신자가 몇 가지 더 많은 메소드를 가지고있는 상황에서 작업을 수행하기 위해 테스트하는 함수 중 하나입니다. – Avicena00

6

여기 WaitHandle이를 사용 가능한 접근 방법은 다음과 같습니다

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     using (ManualResetEvent waitHandle = new ManualResetEvent(false)) 
     { 
      // have to initialize this variable, otherwise the compiler complains when it is used later 
      int randomNumber = 0; 

      Thread thread1 = new Thread(new ThreadStart(() => 
      { 
       randomNumber = _sender.GenerateNumber(); 

       try 
       { 
        // now that we have the random number, signal the wait handle 
        waitHandle.Set(); 
       } 
       catch (ObjectDisposedException) 
       { 
        // this exception will be thrown if the timeout elapses on the call to waitHandle.WaitOne 
       } 
      })); 

      // begin receiving the random number 
      thread1.Start(); 

      // wait for the random number 
      if (waitHandle.WaitOne(/*optionally pass in a timeout value*/)) 
      { 
       _receiver.TakeRandomNumber(randomNumber); 
      } 
      else 
      { 
       // signal was never received 
       // Note, this code will only execute if a timeout value is specified 
       System.Console.WriteLine("Timeout"); 
      } 
     } 
    } 
} 

public class Sender 
{ 
    public int GenerateNumber() 
    { 
     Thread.Sleep(2000); 

     // http://xkcd.com/221/ 
     int randomNumber = 4; // chosen by fair dice role 

     return randomNumber; 
    } 
} 

public class Receiver 
{ 
    public void TakeRandomNumber(int randomNumber) 
    { 
     // do something 
     System.Console.WriteLine("Received random number: {0}", randomNumber); 
    } 
} 


난 그냥에서 Task<TResult> 클래스를 사용하여 위의 예에 해당하는 코드입니다 무슨 생각을 제공하기 위해 내 대답을 업데이트하고 싶었다. NET 4는 Jon Skeet이 대답했다. 신용은 그를 지적하기 위해 그에게갑니다. 고마워, 존. 나는 그 수업을 아직 사용할 이유가 없었고 사용하기가 얼마나 쉬운지를 보았을 때 즐겁게 놀랐다.

이 클래스를 사용하면 얻을 수있는 성능상의 이점 외에도 Task<TResult> 클래스를 사용하여 동일한 코드를 작성하는 것이 훨씬 쉬워 진 것 같습니다. 예를 들어, 위와 같이 다시 작성할 수 Main 메서드의 본문은 다음과 같습니다 : 당신이 작업에 대한 시간 제한을 지정할 필요가 없으며 무기한 대기하는 내용 인 경우가 끝날 때까지

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // wait for up to 5 seconds for the getRandomNumber task to complete 
     if (getRandomNumber.Wait(5000)) 
     { 
      _receiver.TakeRandomNumber(getRandomNumber.Result); 
     } 
     else 
     { 
      // the getRandomNumber task did not complete within the specified timeout 
      System.Console.WriteLine("Timeout"); 
     } 

는, 당신은 쓸 수 있습니다 더 적은 코드 사용 :

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // accessing the Result property implicitly waits for the task to complete 
     _receiver.TakeRandomNumber(getRandomNumber.Result); 
+0

감사합니다. – Avicena00

+0

엄지 손가락 !!!!!! – Avicena00

+0

@AintMeBabe - .NET 4를 사용하는 경우 Jon Skeet의 답변을 확인하는 것이 좋습니다. 'Task '클래스를 사용하면 훨씬 적은 코드로 똑같은 일을 할 수있는 것처럼 보입니다. –

0

두 스레드 간의 통신을 구현하는 "최상의"방법은 실제로 전달해야 할 내용에 달려 있습니다. 귀하의 사례는 고전적인 생산자/소비자 문제로 보입니다. 동기화 대기열을 사용합니다. 동기화 된 컬렉션에 대한 MSDN 설명서를 확인하십시오. Queue.Synchronized 메서드를 사용하여 Queue 객체에 대한 동기화 된 래퍼를 가져올 수 있습니다. 그런 다음 제작자 스레드에서 Enqueue() 및 소비자 호출 Dequeue()를 호출합니다.