2009-05-14 3 views
4

아래 코드를 살펴보십시오. 이것이 ENTIRE 클래스라고 가정합니다. 나는 어떤 코드도 생략하지 않았다. 이것은 말 그대로 문자 그대로입니다.C# multithreading

주 프로그램 루프에서이 클래스를 인스턴스화하고 myExample.Add (무엇이든)를 수시로 호출하면 Dequeue() 및 Enqueue()를 잠그지 않아 발생하는 문제에 대해 걱정할 필요가 있습니까?

public class Example<T> 
{ 
    private Queue<T> q = new Queue<T>(); 

    public Example() 
    { 
     new Thread(() => 
     { 
      while (true) 
      { 
       if (this.q.Count > 0) 
       { 
        var item = this.q.Dequeue(); 
       } 
       Thread.Sleep(1); 
      } 
     }).Start(); 
    } 

    public void Add(T val) 
    { 
     this.q.Enqueue(val); 
    } 
} 

this.q.Enqueue (val)가 this.q.Dequeue()와 동시에 호출되면 어떻게됩니까?

+0

(귀하의 코멘트에 회신) –

답변

2

에 따라 다릅니다. :) 여러개의 쓰레드를 가진 Example을 호출하면 큐의 수를 확인하는 것과 dequeue를 비교하는 사이에 경쟁 조건이 생깁니다. 당신은 당신이 이륙하든 상관하지 않기 때문에 예를 들어 ...

T1 Call Example 
T2 Call Example 
T2 check Q.Count > 0 (yes) 
T1 check Q.count > 0 (yes) 
T2 dequeue 
T1 dequeue OOPS! 

여러 스레드 예를 호출하지 않는 경우

, 당신은 당신이 뭔가를 벗어 것만 아무 문제가 없습니다. 이륙 한 것을 신경 쓰면 Add와 Example 사이의 경쟁 조건이 다시 문제가됩니다.

+0

나는 이것을 처음에는 생각했지만, 큐가 dequed되는 유일한 장소는 하나의 루프 안에있다. 그래서 Example 클래스의 외부는 아무것도 대기열에 넣을 수 없어야하고 wouldn 대기열을 볼 수 없습니다. – uzbones

+0

Example으로 호출하는 각 스레드는 해당 루프에 들어오는 새 스레드를 포크합니다. Example에 10 개의 쓰레드를 보내면 그 루프에서 10 개의 쓰레드가 실행됩니다. 그 스레드는 절대로 돌아 오지 않습니다. 따라서 시간이 지남에 따라 생성되며 경쟁 상태가됩니다. –

+0

그들은 정적 클래스가 아니므로 모두 별도의 개체가 될 것이고 생성자는 스레드를 만드는 것이므로 개체 당 스레드가 항상 1 개가됩니다. – uzbones

0

난 당신이

this.q.Enqueue(val); 

을 의미

this.queue.Enqueue(val); 

에 의해 가정?

그렇다면 어떤 종류의 잠금을 수행해야합니다. 컬렉션은 본질적으로 스레드로부터 안전하지 않습니다. 항상 한 스레드에서 제거하고 항상 다른 스레드에서 추가한다고 생각하면 문제가 없을 수도 있지만 안전하지 않은 이유는 무엇입니까?

+0

대기열이 언제든지 내부 배열의 크기를 조정해야하기 때문에 안전하다고 생각하지 않습니다. –

+0

완전히 대기열에 들어가기 전에 무언가를 큐에서 제거하거나 내부 배열의 동일한 위치에 두 항목을 쓸 수 있기 때문에 대기열에 문제가있을 수 있다고 생각합니다. – uzbones

1

크리스

개인 정적 필드

readonly static object lockObject = new object(); 

당신의 람다 루프 밖에서 넣어위한

lock(lockObject) 
{ 
    //do stuff 
} 

와 디큐와 인큐을 둘러싸 추가

1

당신이있어 이후 큐를 Dequeue 메소드를 통해 큐에 쓰면 큐를 잠글 수 있습니다. 큐는 다중 판독기에서는 스레드로부터 안전하지만 복수 작성자에서는 사용할 수 없습니다. Queue thread safety.

+0

해당 시나리오의 "판독기"는 Dequeue ("쓰기")가 아닌 foreach입니다. 그와 같이; 실제로는 대기열이 여러 발신자를 유용하게 지원하지 않는다고 말하는 것이 더 간단합니다. 조금도. –

0

안전하다고 생각하는 이유가 표시되지 않습니다.

제 걱정/가정 (두 개의 서로 다른 스레드에서) 동시에 대기열에 넣기와 대기열에 들어감을 입력하면 대기열 인스턴스의 내부 상태가 손상 될 수 있습니다.

8

짧은 버전은 당신에게 큐 해야 동기화에 액세스 할 수 있습니다. Count/Dequeue에는 명백한 스레드 레이스가 있지만 더 중요한 것은 이 없습니다. 작업이 보장됩니다. 내부 상태가 일 수 있으며 손상 될 수 있습니다.

결국 스레드를 종료하는 방법을 원할 것입니다.

차단 대기열을 작성하려면 여기를 참조하십시오. Creating a blocking Queue<T> in .NET.

+0

하지만 왜? 마크, 네가 네가 나보다 똑똑하다는 것을 안다. 그러나이 점들을 얻으려면 분명한 경쟁 조건이 무엇인지 말해줘야한다. :) 나는 내부의 상태에 관해 당신과 동의한다. 그러나 경쟁 조건은 어떨까요? – core

+0

OK -이 경우 경쟁 조건 *은 아마도 중요하지 않습니다. 여러 명의 독자가 없을 것입니다. 그러나 스레딩은 어렵습니다. * 경쟁 조건이 아닌 (잠금이없는) 코드를 읽고 호출 패턴을 이해해야합니다. count/dequeue를 잠그면 레이스의 잠재력이 없다는 것을 분명히하지 않겠습니까? 이것은 또한 나중에 클래스를 확장 할 때 버그 수렵을하지 않아도된다는 것을 의미합니다. –

0

대기열을 수정하는 별도의 스레드를 명시 적으로 작성 중이므로 호출하는 스레드에 관계없이 Add()를 호출하는 것이 안전하지 않습니다.

"if"문 블록은 q.Count를 호출해도 안전하지 않으므로 lock()을 수행 한 다음 Add() 메서드에서 다시 잠글 필요가 있습니다.

관련 문제