2014-09-28 89 views
3

我有一個與設備一起工作的類,以避免在使用設備和串行端口時UI層出現延遲我使用了一個線程,但我的設備僅限於做一次一份工作。 所以,我有一個隊列,當用戶要求做任務被添加到它時,然後我運行一個線程來逐個完成任務。使用一個線程多次執行特定任務C#

每次用戶要求一個任務時,我會檢查線程是否正在運行,如果是,我只是將新任務添加到隊列中,如果沒有,我再次創建線程。這意味着每次隊列都變空時,我應該創建一個新線程。現在我想問問有沒有什麼方法可以重用該線程?由於我只需要一個線程來完成任務,使用線程池是個好主意?由於掛起是一種過時的方法,我不知道用戶什麼時候會要求另一個任務使用wait(),我可以掛起線程並以任何其他方式再次運行它嗎?或者最好再次創建線程,我正確地做對了嗎?

public class Modem 
{ 
    Thread thread; 
    Queue<Task> Tasks = new Queue<Task>(); 
    public Modem() 
    { 
    } 

    public void DoTask(Task s) 
    { 
     Tasks.Enqueue(s); 
     if (thread == null || !thread.IsAlive) 
      thread = new Thread(HandleTasks); 
    } 

    private void HandleTasks() 
    { 
     while (Tasks.Count != 0) 
      SendTaskToModem(Tasks.Dequeue()); 
    } 
} 
+3

爲什麼寫自己的ThreadPool?該框架已經提供了一個。 – 2014-09-28 08:50:38

+0

如何使用線程池來代替?聽起來像是你想要的。 – Automatico 2014-09-28 08:52:06

+0

@HenkHolterman在多線程的情況下不是線程池有用嗎?我的意思是我不能運行更多的一個線程從隊列中選擇任務並將它們傳遞到調制解調器,實際上我需要一個線程來逐個完成任務!或者我誤解了threadpool? – 2014-09-28 08:58:15

回答

2

有沒有什麼辦法重用線程?由於我只需要一個線程到 做任務是使用線程池的好主意嗎?

是的,使用ThreadPool並依靠該框架通常是一個更好的主意,然後旋轉自己的自定義實現。

你可以做的是使用一個後臺線程負責處理你的物品,而另一個負責排隊它們。這是一個簡單的生產者 - 消費者問題。對於這一點,你可以使用一個BlockingCollection

public class Modem 
{ 
    private BlockingCollection<Task> _tasks; 
    public Modem() 
    { 
     _tasks = new BlockingCollection<Task>(); 
    } 

    public void QueueTask(Task s) 
    { 
     _tasks.Add(s); 
    } 

    private Task StartHandleTasks() 
    { 
     return Task.Run(async() => 
     { 
      while (!_tasks.IsCompleted) 
      { 
       if (_tasks.Count == 0) 
       { 
        await Task.Delay(100).ConfigureAwait(false); 
        continue; 
       } 

       Task task; 
       _tasks.TryTake(out task); 

       if (task != null) 
       { 
        // Process item. 
       } 
      } 
     }); 
    } 
} 

這是使用BlockingCollection的一個相當簡單的例子。它具有更多內置功能,例如使用CancellationToken來取消當前正在處理的項目。請注意,您將不得不添加適當的異常處理,取消等。

@ChrFin使用TPL Dataflow實現可以節省您在開始處理任務和旋轉後臺線程時的一些開銷,同時沒有任何項目需要處理。我發佈了這個答案給你另一種解決你的問題的方式。

+0

爲什麼實施自己的「生產者 - 消費者」邏輯如果已經有內置的?你將如何處理「自由運行任務」中的錯誤? – ChrFin 2014-09-28 09:04:51

+0

這是如何實現我自己的生產者 - 消費者邏輯?這只是使用內置類型來滿足他需要的內容。我不確定OP是否需要「TPL Dataflow」的全面架構,尤其是當您將其併發限制爲單個線程時?我將如何處理錯誤?我不確定你是什麼意思。這與在任何隊列處理中處理錯誤有什麼不同? – 2014-09-28 09:06:35

+0

正如我在回答中所說,這是一個相當簡單的例子。 OP將需要採取這種做法,使其適用於所有可能的場景,包括添加錯誤處理機制。我不是說這個例子比使用ActionBlock更好,它只是一個不同的例子。它由OP來決定他想要使用什麼。 – 2014-09-28 09:12:18

2

也有一些是內置了這樣的任務:ActionBlock(不與核心框架分佈,你需要添加Microsoft.Tpl.Dataflow NuGet包)。
如果你創建喜歡:

var actionBlock = new ActionBlock<TASK>(t => DoWork(t), 
    new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 1 }); 

只有一個項目將立即進行處理。

然後你只需撥打:

actionBlock.Post(yourTask); 

和所有「貼」任務是在自己的線程中執行一個後對方。

完成後,您可以撥打actionBlock.Complete();,然後await actionBlock.Completion;。在那裏您還可以檢查發生在DoWork內部的異常情況。

相關問題