1

Queue에 파일 이름을 넣어서 새 파일을 찾고있는 FileSystemWatcher이 있습니다. 별도의 스레드에서 대기열이 작동됩니다. 내 코드가 작동하지만 비동기 프로세스 때문에 정보가 손실 될 수 있는지 질문합니다. (I 네 생각에 내가 어딘가 나사 잠금 식으로 뭔가를해야합니까?) (코드 단순화)BackgroundWorker 및 ConcurrentQueue

public class FileOperatorAsync 
{ 
    private ConcurrentQueue<string> fileQueue; 
    private BackgroundWorker worker; 
    private string inputPath; 

    public FileOperatorAsync(string inputPath) 
    { 
    this.inputPath = inputPath; 
    fileQueue = new ConcurrentQueue<string>(); 
    worker = new BackgroundWorker(); 
    worker.WorkerSupportsCancellation = true; 
    worker.DoWork += worker_DoWork; 
    Start(); 
    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
    try 
    { 
     string file; 
     while (!worker.CancellationPending && fileQueue.TryDequeue(out file)) //As long as queue has files 
     { 
      //Do hard work with file 
     } 
     //Thread lock here? 
     //If now Filenames get queued (Method Execute -> Worker is still busy), they wont get recognized.. or? 
    } 
    catch (Exception ex) 
    { 
     //Logging 
    } 
    finally 
    { 
     e.Cancel = true; 
    } 
    } 

    public void Execute(string file) //called by the FileSystemWatcher 
    { 
    fileQueue.Enqueue(file); 
    Start(); //Start only if worker is not busy 
    } 

    public void Start() 
    { 
    if (!worker.IsBusy) 
     worker.RunWorkerAsync(); 
    } 

    public void Stop() 
    { 
    worker.CancelAsync(); 
    } 

} 
+0

제목이 없으면 이해할 수없는 경우가 아니면 제목에 languge 태그를 포함하지 마십시오. 태그는 이러한 용도로 사용됩니다. –

답변

2

예, Execute에 문제가있을 수 있습니다. worker에 의해 file이 처리되지 않은 상태로 남을 수 있습니다.

두 가지 방법으로 해결할 수 있습니다.
1) 대기중인 모든 파일을 처리 한 후 worker이 완료되지 않습니다. 다음 파일 처리를 위해 AutoResetEvent에서 기다립니다. 이 경우 ExecuteAutoResetEvent.Set으로 전화하여 worker에 알려야합니다.
예 :

AutoResetEvent event; 
... 
// in worker_DoWork 
while(!worker.CancellationPending){ 
    event.WaitOne(); 
    // Dequeue and process all queued files 
} 

... 
// in Execute 
fileQueue.Enqueue(file); 
event.Set(); 

2) 근로자가 모두 처리하는 파일을 대기 한 후 완료 (지금처럼)하지만 여전히 처리하고 다시 한 번 노동자 실행 파일이 있는지 여부를 당신은 BackgroundWorker.RunWorkerCompleted에서 확인할 수 있습니다.
Execute이 사용 중이기 때문에 worker이 시작되지 않은 경우 workerBackgroundWorker.RunWorkerCompleted에서 다시 시작되고 보류 중 file이 처리됩니다.

// in worker_RunWorkerCompleted 
if (!fileQueue.IsEmpty()) 
    Start(); 

:가 아닌 GUI 응용 프로그램에서 BackgroundWorker.RunWorkerCompleted을 사용하기로 결정하는 경우 BackgroundWorker.RunWorkerCompleted 당신이 Execute을 호출 스레드에서 발생하는 경쟁 조건에없는 호출 할 수 있기 때문에 당신은 Start에주의해야 Start. 더 많은 정보는 : 동시에 두 개의 서로 다른 스레드에서 Start()를 호출하는 경우 BackgroundWorker.RunWorkerCompleted and threading

둘 다 볼 수 worker.IsBusy == false 그들은 모두 worker.RunWorkerAsync()를 호출합니다. 다른 스레드보다 조금 늦게 worker.RunWorkerAsync()을 호출하는 스레드는 InvalidOperationException을 던집니다. 따라서 예외 상황을 피하거나 예외 상황이 발생하지 않도록하려면 IsBusy + RunWorkerAsync을 잠글 수있는 중요한 섹션으로 래핑해야합니다.

+0

감사! 두 번째 해결책을 사용했습니다. 예, 그것은 비 GUI 응용 프로그램입니다. 참고 주셔서 감사합니다! "Execute"는 FileSystemWatcher Created Event에 의해 호출되었으므로 이미 다른 스레드에 의해 실행되었지만 여전히 동기식입니까? – JDeuker

+0

@ J.D. 귀하의 질문에 답변하기 위해 내 대답에 한 가지 더 메모를 추가했습니다. 나는 당신의 질문을 정확하게 이해하기를 바랍니다. –

+0

많이 도와 줘서 고마워! – JDeuker

1

하는 큐 인 문제에 대해 걱정할 필요하지 않기하려면 의견에 의해 설명 코드를 봐주세요 우아 자고 것없이 큐가 비어있을 때 알리기 위해 ManualResetEvent 클래스를 사용,

while (!worker.CancellationPending) 
{ 
    while (!worker.CancellationPending && !fileQueue.TryDequeue(out file)) 
    { 
     Thread.Sleep(2000); 
    } 

    if (worker.CancellationPending) 
    { 
     break; 
    } 
    // 
} 

다른 가능성을하고 : 빈과 Start는 작업자 종료하기 전에라고, 당신은 모든 작업자 방법을 떠나지 않을 시도 할 수 있습니다 비어있는 것을 중지합니다.

+0

문제 자체가 대기열이 아닙니다. 대기열이 안정적으로 작동합니다. 나는 dequeuing이 끝난 후에 엔큐 된 아이템에 대해 걱정하고 있습니다. 내가 여기에 "// 여기에 잠금 장치를 두는 곳"을 보아라. Comment – JDeuker

+0

@ J.D. 무엇을 성취하기를 원하시는지는 분명하지 않습니다. 거기에 코드가 없으므로 잠금이 필요하지 않습니다. 아이템 추가에 대해서도'Enqueue' 메소드가 동기화됩니다. – BartoszKP

+0

예, 그 이후에는 많은 코드가 없지만, 수 밀리 초가 지나갈 수 있다고 생각합니다 ... 가능한 한 안전하게 만들고 싶습니다. – JDeuker