문제

이것을 올바르게 동기화하는 방법은 무엇입니까? 현재 가능합니다 SetData 이후에 호출됩니다 e.WaitOne() 그렇게 완료되었습니다 d 이미 다른 값으로 설정할 수 있습니다. 잠금 장치를 삽입하려고했지만 교착 상태가되었습니다.

AutoResetEvent e = new AutoResetEvent(false);

public SetData(MyData d)
{
   this.d=d;
   e.Set();    // notify that new data is available
}

// This runs in separate thread and waits for d to be set to a new value
void Runner() 
{    
   while (true)
   {
      e.WaitOne();  // waits for new data to process
      DoLongOperationWith_d(d);
   }
}

최상의 솔루션은 새로운 부울 변수를 소개하는 것입니다. dataAlreadyBeenSetAndWaitingToBeProcessed 그것은 설정되어 있습니다 SetData 진실과 끝에 DoLongOperationWith_d 사실로 설정할 수 있습니다 SetData 이 변수로 설정된 상태로 호출되면 반환 할 수 있습니까?

도움이 되었습니까?

해결책

이것은 테스트되지 않았지만 .NET 기반 프리미티브로이를 수행하는 우아한 방법입니다.

class Processor<T> {
    Action<T> action;
    Queue<T> queue = new Queue<T>();

    public Processor(Action<T> action) {
        this.action = action;
        new Thread(new ThreadStart(ThreadProc)).Start();
    }

    public void Queue(T data) {
        lock (queue) {
            queue.Enqueue(data);
            Monitor.Pulse(queue); 
        }            
    }

    void ThreadProc() {
        Monitor.Enter(queue);
        Queue<T> copy;

        while (true) {                 
            if (queue.Count == 0) {
                Monitor.Wait(queue);
            }

            copy = new Queue<T>(queue);
            queue.Clear();
            Monitor.Exit(queue);

            foreach (var item in copy) {
                action(item); 
            }

            Monitor.Enter(queue); 
        }
    }
}

예제 프로그램 :

class Program {

    static void Main(string[] args) {

        Processor<int> p = new Processor<int>((data) => { Console.WriteLine(data);  });
        p.Queue(1);
        p.Queue(2); 

        Console.Read();

        p.Queue(3);
    }
}

이것은 큐치가 아닌 버전이며 큐 버전이 선호 될 수 있습니다.

object sync = new object(); 
AutoResetEvent e = new AutoResetEvent(false);
bool pending = false; 

public SetData(MyData d)
{
   lock(sync) 
   {
      if (pending) throw(new CanNotSetDataException()); 

      this.d=d;
      pending = true;
   }

   e.Set();    // notify that new data is available
}

void Runner() // this runs in separate thread and waits for d to be set to a new value
{

     while (true)
     {

             e.WaitOne();  // waits for new data to process
             DoLongOperationWith_d(d);
             lock(sync) 
             {
                pending = false; 
             }
     }
}

다른 팁

여기에는 두 가지 문제가있는 시나리오가 있습니다.

1:

  • dolongoperationwith_d (d) 마감.
  • setData ()가 호출되어 d에 새 값을 저장합니다.
  • e.waitone ()이 호출되지만 값이 이미 설정되었으므로 스레드는 영원히 대기합니다.

그것이 당신의 관심사라면, 나는 당신이 긴장을 풀 수 있다고 생각합니다. 로부터 선적 서류 비치, 우리는 그것을 봅니다

autoresetevent가 신호 상태에있는 동안 스레드가 Waitone을 호출하면 스레드가 차단되지 않습니다. autoresetevent는 스레드를 즉시 방출하고 서명되지 않은 상태로 돌아갑니다.

그래서 그것은 문제가 아닙니다. 그러나 SetData ()가 호출되는 방법과시기에 따라 더 심각한 것을 다룰 수 있습니다.

2:

  • SetData ()가 호출되어 D에 새 값을 저장하고 러너를 깨우는 것입니다.
  • dolongoperationwith_d (d)가 시작됩니다.
  • setData ()가 다시 호출되어 d에 새 값을 저장합니다.
  • setData ()가 다시 호출됩니다! D의 오래된 가치는 영원히 손실됩니다. dolongoperationwith_d ()는 절대 호출되지 않습니다.

그것이 당신의 문제라면, 그것을 해결하는 가장 간단한 방법은 동시 대기열입니다. 구현이 많이 있습니다.

2 개의 이벤트를 사용할 수 있습니다.

AutoResetEvent e = new AutoResetEvent(false);
AutoResetEvent readyForMore = new AutoResetEvent(true); // Initially signaled

public SetData(MyData d)
{
   // This will immediately determine if readyForMore is set or not.
   if( readyForMore.WaitOne(0,true) ) {
     this.d=d;
     e.Set();    // notify that new data is available
  }
  // you could return a bool or something to indicate it bailed.
}

void Runner() // this runs in separate thread and waits for d to be set to a new value
{

     while (true)
     {

             e.WaitOne();  // waits for new data to process
             DoLongOperationWith_d(d);
             readyForMore.Set();
     }
}

이 접근법으로 할 수있는 일 중 하나는 SetData가 시간을 가져 와서 전달하는 것입니다. WaitOne. 그러나 당신은 shoudl이 조사한다고 생각합니다 ThreadPool.QueueUserWorkItem.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top