2010-07-10 4 views
0

나는 List와이 List를 사용하는 두 개의 스레드를 가지고 있습니다.동일한 변수를 사용하는 두 개의 스레드에서 문제가 발생합니다.

첫 번째 스레드가 새 연결을 받고 각각의 새 연결이 목록에 추가됩니다.

두 번째 스레드가 List를 반복하여 연결을 처리합니다 (foreach 사용).

두 번째 스레드가 목록에서 반복되는 동안 루프가 끝나기 전에 목록이 변경되는 경우가 있습니다. 나는 심지어리스트의 새로운 복사본을 만들고 그것을 반복 해 보았다. 그러나 다른 문제를 일으킨다.

새로운 연결을 처리 할 새 스레드를 만들고 싶지 않습니다. 너무 많은 스레드가 성능을 저하시킬 수 있다는 것을 알고 있기 때문입니다. 연결을 처리하는 다른 방법이 있습니까?

+3

스레딩 방법을 배우는 경우 "너무 많은 스레드가 성능을 저하시킬 수 있습니다"라고 말할 때 다른 사용자를 믿지 마십시오. 스스로 해보고 자신의 상황에서 한계가 실제로 무엇인지 알아보십시오. 당신은 훨씬 더 많이 배우게 될 것입니다. –

+0

목록을 복사 할 때 어떤 종류의 문제가 발생합니까? – SwDevMan81

+0

대상 배열의 크기가 올바르지 않습니다 (복사가 완료되기 전에 배열이 변경됨). –

답변

3

2 문제.

1) 목록을 잠글 필요가 있습니다. 목록에 대해 상호 독점적으로 액세스 할 수 있도록해야합니다. 따라서 목록이 수정되는 동안 열거 될 수 없습니다.

우아
class Mailbox { 
    List<int> list; 

    void Send(int a) { 
     lock(list) { 
       list.Add(a); 
     } 
    } 

    int Receive() { 
     lock(list) { 
      // Enumerate 
      return ...; 
     } 
     } 
} 

더, 당신은 BlockingCollection 같은 Concurrent 네임 스페이스의 새로운 컬렉션 중 하나를 사용할 수 있습니다 첫 번째 솔루션은 잠금을 사용하는 것입니다. 후자는 열거 형 (enumeration-safe)이 아니지만 생성자가 객체를 삽입하는 동안 객체를 검색하는 데 사용할 수있는 Take() 메소드를 제공합니다.

2) gazillion 스레드를 생성하지 마십시오. .NET thread pool을 사용하여 원하는만큼 많은 요청을 큐에 넣을 수 있습니다. 프레임 워크는 시스템을 죽이지 않고 실제 스레드에 매핑하도록 처리합니다.

+0

'BlockingCollection'은 * 수정 사항 만 목록에 동기화합니다. 반복에는 여전히 명시 적 잠금이 필요합니다. –

+0

예, 맞습니다. 열거 형을 제거해야하며 대신 Take()를 사용할 수 있습니다. – Mau

-4

난 정말이에 대해 잘 모르겠지만, 내 마음에 온 첫번째 생각했다 :

스토어리스트의 길이를 루프가

while (var i < lengthoflist) 
{ 
//whatever fancy stuff your code does 
i++; 
} 

갈 수 있도록하지만 내가 아는 소켓에 관한 것, 그건 제가 생각한 일반적인 아이디어였습니다. 그래서 그것이 작동하는지 모르겠습니다.

+0

(안전하게) 작동하지 않습니다. 그것은 아마 던지지 않을 것이지만, 그것은 항목이나 물건을 건너 뛸지도 모른다. –

1

가장 쉬운 해결책은 각 스레드의 목록에 lock을 사용하는 것입니다.

첫번째 쓰레드

lock(yourList) 
{ 
    yourList.Add(...); 
} 

두번째 쓰레드

lock(yourList) 
{ 
    foreach(var item in yourList) 
    { 
     ... 
    } 
} 

이 두번째 쓰레드의 반복의 중간에있는 동안 연결에 추가되는 것을 제 실을 방지 할 것이다. 두 번째 스레드가 목록을 반복하고 첫 번째 스레드가 코드의 lock -ed 섹션을 입력하려고하면 두 번째 스레드가 목록에서 반복을 완료 할 때까지 대기합니다.

+0

@ 주케 : 예, 대답의 마지막 부분에 나와 있습니다. 이것은 OP가 요청한 것처럼 들렸습니다. –

1

다른 사람들도 작성했듯이 잠금을 사용하여이 두 스레드의 동시성을 관리해야합니다.

여러 스레드를 사용하지 않는 한, 스레드의 수에 크게 달려 있다고 생각합니다. 당신이 작업하는 소켓 연결이 몇 개 있다면, 각각의 스레드에서 동기식 읽기를 수행하는 것이 좋습니다. 하지만 많은 소켓 연결에 대해 이야기하고 있다면 각 소켓마다 전용 스레드를 사용하지 않을 것입니다.

여러 소켓에서 가장 효율적인 방법은 비동기 읽기 (Socket.BeginReceive())를 사용하는 것입니다. 후드 아래에서 이러한 비동기 메서드는 매우 효율적으로 I/O Completion Ports을 사용합니다. 비동기 소켓 메소드를 사용하여 수천 개의 동시 연결을 처리 할 수있는 사용자 정의 TCP 서버를 구현하는 것은 상대적으로 쉽습니다.

관련 문제