2010-06-30 4 views
1

동일한 속성을 가져오고 설정하는 네 개의 스레드를 실행 중입니다. 내가 브레이크 포인트를 사용하면 예상대로 결과를 얻을 수 있지만 직접 실행하면 최종 업데이트 결과가 표시됩니다.스레드의 setter 속성을 잠그는 방법

여기에 코드 내가 모든 메시지 상자에 8003를 얻을 실행될 때

int Port { get; set; } 
Thread[] tMain= new Thread[4]; 

public void btnListen_Click(object sender, EventArgs e) 
     { 
      for (int i = 0; i < 4; i++) 
      { 
       tMain[i] = new Thread(Connect); 
       tMain[i].IsBackground = true; 
       tMain[i].Start(8000+i); 
      } 
     } 


public void Connect(object _port) 
     { 
      try 
      { 
       lock ((object)Port) 
       { 
        Port = (int)_port; 
       } 
       IPEndPoint ie = new IPEndPoint(IPAddress.Any, Port); 
       Socket listenSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
       listenSock.Bind(ie); 
       listenSock.Listen(100); 
       Thread tListen = new Thread(() => StartListening(listenSock, Port)); 
       tListen.IsBackground = true; 
       tListen.Start(); 
      } 
      catch (SocketException ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 

public void StartListening(Socket _socket, int port) 
     { 
      Socket tempSock,listenerSocket=(Socket)_socket; 
      MessageBox.Show("Thread Started"+port.ToString()); 
      while (true) 
      { 
       MessageBox.Show("Waiting For Connection"); 
       tempSock = listenerSocket.Accept(); 

       Thread tInner = new Thread(ProcessMessages); 
       tInner.IsBackground = true; 
       tInner.Start(tempSock); 
      } 
     } 

지금 내가 이상 여기에 무엇을보고 내 코드입니다. 처음 3 개의 스레드가 액세스 할 때 그 사이에 속성을 수정할 수 없었기 때문일 수 있습니다. 이 경우 잠금을 얻는 방법.

+0

왜 실제로 "포트"속성이 필요합니까? 이 코드에는 많은 문제가 있지만 먼저 해당 속성에 대한 필요성부터 살펴 보겠습니다. 단순히 그 코드와 관련된 모든 코드를 제거하면 어떨까요? IPEndPoint 생성자에 대한 호출에서 "Port"대신'(int) _port'를 전달하면됩니다. 그게 모든 문제를 해결하지 않겠습니까? –

+0

@Lasse : 이전에 (int) _port 만 사용했는데 성공적으로 실행 한 다음 속성으로 대체하여 일부 RND를 수행하고이 문제를 발견했습니다. 그래서 이유가 있습니다. 그렇지 않으면 나는 컬렉션을 사용하는 아이디어도 가지고 있었다. –

답변

2

이 코드는 처음에는 리팩토링이 필요합니다. 너무 많은 스레드가 스팬되어 있으며 매우 좁은 컨텍스트에서 모두 필요합니다!

짧은 대답은 :

문제는 Connect 기능은 시간 (또는 순서) 당신이 될 것으로 기대 아니라 단지 루프가 완료되면에서 호출되지 않는다는 사실에 요약된다.

긴 대답 : 함수 내에서 예를 범위의 변수/속성을 사용하려고 할 때

이 동시성 문제의 매우 일반적인 시나리오입니다. 내가 알 수있는 한, Port에 대해 원하는 값을 얻지 못하는 문제는 직접 잠금 자체와 아무 관련이 없습니다. (그런 식으로 해결할 수는 있지만 정상적으로는 생각할 수 없습니다.) 궁극적으로 프로세서 레벨에서 다른 스레드에 시간 블록을 할당하는 방법을 제어 할 수 없으므로 어떤 함수가 실행되는지 알지 못합니다 어떤 순서로. 또한 상태가 좋고 상태를 유지하지 않는 (기능적) 디자인의 원칙을 혼합하는 것으로 보이는데, 이는 문제를 일으킬 수 있습니다. 하나에 붙어 -이 경우에는 후자가 바람직합니다 - 훨씬 더 성공할 것입니다.

그래서 나는 멀티 스레딩을 매우 복잡하게 읽는 것이 유익 할 것이라는 말을 듣고 친절하게 여기기를 바랍니다. 이것은 매우 복잡한 주제입니다. 그리고 몇 가지 일반적인 원칙을 실천합니다. 행운을 빕니다!

+0

@ Noldorin : 가혹한 느낌을주는 것과 같은 것은 없습니다. 나는 이것들에 대해 아는 것이 나를위한 기쁨이다. 이것이 소켓 생성 및 멀티 스레딩에 대한 첫 번째 프로그램 이었지만. 그리고 지금은 루핑이 종료 된 후에 스레드가 호출되고 있다고 말했기 때문에 스레드의 새로운 숨겨진 기능이었습니다. 여기에 제가 사용하는 2-3 가지 해결책이 있습니다. 컬렉션을 사용하거나 포트의 정적 값을 사용합니다. 다른 일을 할 수 있고 내가 자물쇠를 가져 가면 어떻게 생각하니? 이 시나리오에서 잠금을 설정할 수 있습니까? 내가 생각하기에 락은 가능하지 않다. –

+0

당신이 설명했듯이 각 쓰레드는 루프가 끝난 후에 시작될 것이다. –

+0

가장 확실한 해결책은 아마도'Port' 클래스 변수를 제거하는 것일뿐입니다. 어쨌든 필요하지 않습니다. 모든 것을 기능적으로 수행하고 매개 변수로 물건을 전달하십시오. – Noldorin

관련 문제