2014-01-08 3 views
1

xml 파일을 연결된 목록 대기열에서 처리 할 Windows 서비스가 있습니다. 큐에있는 파일은 파일을 만들 때 FileSystemWatcher 이벤트에 의해 추가되었습니다.ProcessingQueue.Count가 다중 스레딩 응용 프로그램에서 올바른지 확인하십시오.

namespace XMLFTP 
{ 
    public class XML_Processor : ServiceBase 
    { 
     public string s_folder { get; set; } 
     public XML_Processor(string folder) 
     { 
      s_folder = folder; 
     } 
     Thread worker; 
     FileSystemWatcher watcher; 
     DirectoryInfo my_Folder; 
     public static AutoResetEvent ResetEvent { get; set; } 
     bool running; 
     public bool Start() 
     { 
      my_Folder = new DirectoryInfo(s_folder); 
      bool success = true; 
      running = true; 
      worker = new Thread(new ThreadStart(ServiceLoop)); 
      worker.Start(); 
      // add files to queue by FileSystemWatcher event 
      return (success); 
     } 
     public bool Stop() 
     { 
      try 
      { 
       running = false; 
       watcher.EnableRaisingEvents = false; 
       worker.Join(ServiceSettings.ThreadJoinTimeOut); 
      } 
      catch (Exception ex) 
      { 
       return (false); 
      } 
      return (true); 
     } 
     public void ServiceLoop() 
     { 
      string fileName; 
      while (running) 
      { 
       Thread.Sleep(2000); 
       if (ProcessingQueue.Count > 0) 
       { 
        // process file and write info to DB. 
       } 
      } 
     } 

     void watcher_Created(object sender, FileSystemEventArgs e) 
     { 
      switch (e.ChangeType) 
      { 
       case WatcherChangeTypes.Created:// add files to queue 
      } 
     } 
    } 
} 

스레드 안전 문제 일 수 있습니다. ProcessingQueue.Count의 액세스가 로크에 의해 보호되지 않기 때문에 다른 스레드는 "큐"을 바꾸는 경우

 while (running) 
     { 
      Thread.Sleep(2000); 
      if (ProcessingQueue.Count > 0) 
      { 
       // process file and write info to DB. 
      } 
     } 

의 개수는 변화 할 수있다. 결과적으로 프로세스 파일 부분이 실패 할 수 있습니다. 잠금이 조기에 해제로

public static int Count 
{ 
get { lock (syncRoot) return _files.Count; } 
} 

: 당신이뿐만 Count 속성을 구현하는 경우 그 또한 사건.

내 두 가지 질문 :

  1. 어떻게 ProcessingQueue.Count이 올 수 있도록? 내가 .NET 프레임 워크 4.5 BlockingCollection 기술을 사용하는 경우
  2. 는, 샘플 코드 등 :

    class ConsumingEnumerableDemo 
    { 
        // Demonstrates: 
        //  BlockingCollection<T>.Add() 
        //  BlockingCollection<T>.CompleteAdding() 
        //  BlockingCollection<T>.GetConsumingEnumerable() 
        public static void BC_GetConsumingEnumerable() 
        { 
         using (BlockingCollection<int> bc = new BlockingCollection<int>()) 
         { 
    
          // Kick off a producer task 
          Task.Factory.StartNew(() => 
          { 
           for (int i = 0; i < 10; i++) 
           { 
            bc.Add(i); 
            Thread.Sleep(100); // sleep 100 ms between adds 
           } 
    
           // Need to do this to keep foreach below from hanging 
           bc.CompleteAdding(); 
          }); 
    
          // Now consume the blocking collection with foreach. 
          // Use bc.GetConsumingEnumerable() instead of just bc because the 
          // former will block waiting for completion and the latter will 
          // simply take a snapshot of the current state of the underlying collection. 
          foreach (var item in bc.GetConsumingEnumerable()) 
          { 
           Console.WriteLine(item); 
          } 
         } 
         } 
        } 
    

샘플에 대기열에 내 동적 계수를 적용하는 방법, 반복 절 등의 일정 (10)를 사용 그것?

답변

3

BlockingCollection을 사용하면 카운트를 알 필요가 없습니다. 대기열이 비어 있고 IsCompleted이 참이 될 때까지 소비자는 항목 처리를 계속합니다. 그래서 당신은 이것을 가질 수 있습니다 :

var producer = Task.Factory.StartNew(() => 
{ 
    // Add 10 items to the queue 
    foreach (var i in Enumerable.Range(0, 10)) 
     queue.Add(i); 

    // Wait one minute 
    Thread.Sleep(TimeSpan.FromMinutes(1.0)); 

    // Add 10 more items to the queue 
    foreach (var i in Enumerable.Range(10, 10)) 
     queue.Add(i); 

    // mark the queue as complete for adding 
    queue.CompleteAdding(); 
}); 

// consumer 
foreach (var item in queue.GetConsumingEnumerable()) 
{ 
    Console.WriteLine(item); 
} 

소비자는 큐를 비우는 처음 10 개의 항목을 출력합니다. 그러나 제작자가 CompleteAdding을 호출하지 않았기 때문에 소비자는 대기열에서 계속 차단할 것입니다. 생산자가 쓰는 다음 10 개 항목을 파악합니다. 그런 다음 대기열이 비어 있고 IsCompleted == true이므로 소비자가 종료됩니다 (GetConsumingEnumerable이 대기열의 끝에옵니다).

언제든지 Count을 확인할 수 있지만 얻을 수있는 값은 단지 스냅 샷입니다. 당신이 그것을 평가할 때까지, 생산자 또는 소비자가 대기열을 수정하고 그 수를 변경했을 가능성이 높습니다. 그러나 그것은 중요하지 않아야합니다. CompleteAdding으로 전화하지 않는 한 소비자는 품목을 계속 기다릴 것입니다.

생산자가 작성하는 항목 수가 일정하지 않아도됩니다. 예를 들어 내 Simple Multithreading 블로그 게시물에서 필자는 파일을 읽고 소비자가 서비스하는 BlockingCollection에 항목을 쓰는 제작자를 보여줍니다. 제작자와 소비자가 동시에 실행되며 제작자가 파일의 끝에 도달 할 때까지 모든 것이 진행됩니다.

+0

멋진데! 코드에서 IsCompleted는 어디에 있습니까? –

+0

@Love :'GetConsumingEnumerable'은'IsCompleted'를 검사합니다. 이것은'BlockingCollection' 클래스의 속성입니다. –

관련 문제