2009-12-18 8 views
3

이 구현에서 왜 stopped이 아닌지 알 수 없습니다. volatile - 다른 스레드가이를 업데이트하면 올바르게 반영됩니까?정상적으로 작업자 스레드 종료

둘째로 원자 (!Stopping)를 테스트하고 있습니까?

using System; 
using System.Threading; 

/// <summary> 
/// Skeleton for a worker thread. Another thread would typically set up 
/// an instance with some work to do, and invoke the Run method (eg with 
/// new Thread(new ThreadStart(job.Run)).Start()) 
/// </summary> 
public class Worker 
{ 
    /// <summary> 
    /// Lock covering stopping and stopped 
    /// </summary> 
    readonly object stopLock = new object(); 
    /// <summary> 
    /// Whether or not the worker thread has been asked to stop 
    /// </summary> 
    bool stopping = false; 
    /// <summary> 
    /// Whether or not the worker thread has stopped 
    /// </summary> 
    bool stopped = false; 

    /// <summary> 
    /// Returns whether the worker thread has been asked to stop. 
    /// This continues to return true even after the thread has stopped. 
    /// </summary> 
    public bool Stopping 
    { 
     get 
     { 
      lock (stopLock) 
      { 
       return stopping; 
      } 
     } 
    } 

    /// <summary> 
    /// Returns whether the worker thread has stopped. 
    /// </summary> 
    public bool Stopped 
    { 
     get 
     { 
      lock (stopLock) 
      { 
       return stopped; 
      } 
     } 
    } 

    /// <summary> 
    /// Tells the worker thread to stop, typically after completing its 
    /// current work item. (The thread is *not* guaranteed to have stopped 
    /// by the time this method returns.) 
    /// </summary> 
    public void Stop() 
    { 
     lock (stopLock) 
     { 
      stopping = true; 
     } 
    } 

    /// <summary> 
    /// Called by the worker thread to indicate when it has stopped. 
    /// </summary> 
    void SetStopped() 
    { 
     lock (stopLock) 
     { 
      stopped = true; 
     } 
    } 

    /// <summary> 
    /// Main work loop of the class. 
    /// </summary> 
    public void Run() 
    { 
     try 
     { 
      while (!Stopping) 
      { 
       // Insert work here. Make sure it doesn't tight loop! 
       // (If work is arriving periodically, use a queue and Monitor.Wait, 
       // changing the Stop method to pulse the monitor as well as setting 
       // stopping.) 

       // Note that you may also wish to break out *within* the loop 
       // if work items can take a very long time but have points at which 
       // it makes sense to check whether or not you've been asked to stop. 
       // Do this with just: 
       // if (Stopping) 
       // { 
       //  return; 
       // } 
       // The finally block will make sure that the stopped flag is set. 
      } 
     } 
     finally 
     { 
      SetStopped(); 
     } 
    } 
} 

편집

이 코드는 an article written by Jon Skeet에서입니다.

+2

Jon Skeet이 어떻게 관련이 있습니까? – YOU

+0

@ S.Mark : 'Jon Skeets'페이지에서 작업자 스레드를 종료하는 방법에 대해 설명합니다. –

+2

@ S.Mark ... 프로그래밍 관련 내용은 Jon Skeet과 관련이 있습니다 .... Jon Skeet 사실이어야합니다! http : //meta.stackexchange.com/questions/9134/jon-skeet-facts – James

답변

6

lock 내부에서만 액세스 할 수 있기 때문에. A lock은 최신 값을 볼 수 있도록합니다.

원 자성 (여기서는 동기화라고 생각합니까?); 그럴 확률은 없다. Stopping이 동기화 된 경우에도 우리가 가지고있는 lock을 종료하자마자 더 이상 값이 최신이라고 믿을 수 없습니다. 따라서 !StoppingStopping보다 더 이상 동기화되지 않습니다. 중요한 것은 우리가 적어도 우리가 최근에 확인했음을 안다는 것입니다. 깃발이 바뀌는 딱딱한 케이스가 있습니다 직후에 확인해 봅니다. 그러나 괜찮습니다. 우리가 점검했을 때, 우리가 계속해야한다는 것이 사실이었습니다.

+0

나는 이것을 이해 했느냐? 잠금을 얻을 때마다 레지스터가 플러시되고 부실 값을 읽지 않습니까? 내가 단단한 루프에서 자물쇠를 얻으면 다르게 넣어 줘요. 휘발성이 필요하지 않나요? 이제까지? –

+0

모든 ** 다른 ** 스레드가 (동일한) 잠금을 보유하고있을 때 필드를 업데이트하는 경우에만 그렇습니다. 다른 스레드가 잠금을 얻지 않고 * 필드를 업데이트하면 모든 내기가 꺼집니다. –

1

this entry on SO을 참조하십시오. 잠금이 휘발성보다 선호되는 이유를 설명합니다. 이 코드의

+0

그러나이 예제는 링크 된 항목에서 "휘발성은 실제로 어떤 용도로 좋은가"범주에 속하지 않습니까?중지 또는 중지를 false로 설정하는 방법이 없으므로 어떠한 경쟁 조건도 존재할 수 없습니다. – Niki

2

문제는 C# 언어 사양의 3.10 절에 정의 된 각각의 실행 쓰레드의 부작용이 중요한 실행 지점에서 보존되도록 C# 프로그램의 진행

실행. 부작용은 휘발성 필드의 읽기 또는 쓰기, 비 휘발성 변수에 대한 쓰기, 외부 리소스에 대한 쓰기 및 예외 발생으로 정의됩니다. 이러한 부작용의 순서를 보존해야하는 중요한 실행 지점은 휘발성 필드 (§10.5.3), 잠금 문 (§8.12) 및 스레드 생성 및 종료입니다.

즉, 잠금 문은 중지 된 필드를 volatile로 선언 할 필요가 없도록하기에 충분한 보증입니다.

lock 문이 단순히 Monitor.Enter() 및 Exit() 메서드를 호출하기 때문에이 규칙이 JIT 컴파일러에 의해 구현되는 방법은 흥미로운 질문입니다. 나는이 메소드에 대한 특별한 지식이 없다고 생각한다. Enter() 호출 이후에 시작되는 try 블록을 입력하는 것의 부작용이라고 생각한다. 그러나 그것은 단지 추측입니다.