2011-11-07 73 views
13

從我能告訴我有誤導的信息位。我需要在後臺運行一個單獨的線程。如何保證使用Task.StartNew方法時創建的新線程

目前,我不喜歡這樣寫道:

var task = Task.Factory.StartNew 
     (CheckFiles 
      , cancelCheckFile.Token 
      , TaskCreationOptions.LongRunning 
      , TaskScheduler.Default);//Check for files on another thread 

private void CheckFiles() 
{ 
    while (!cancelCheckFile.Token.IsCancellationRequested) 
    { 
     //do stuff 
    } 
} 

這始終是我創建了一個新的線程。但是,經過多次討論後,即使它被標記爲LongRunning也不能保證會創建新的線程。

在過去,我已經做了這樣的事情:

thQueueChecker = new Thread(new ThreadStart(CheckQueue)); 
thQueueChecker.IsBackground = true; 
thQueueChecker.Name = "CheckQueues" + DateTime.Now.Ticks.ToString(); 
thQueueChecker.Start(); 


private void CheckQueue() 
{ 
    while (!ProgramEnding) 
    { 
      //do stuff 
    } 
} 

你會建議我回去這種方法,以保證新的線程使用?

+0

'LongRunning'只是調度程序的一個提示 - 如果你絕對必須總是有一個新的線程,你將不得不創建一個。 –

+0

花哨添加作爲答案? – Jon

+0

謝謝喬恩:) –

回答

5

LongRunning只是調度程序的一個提示 - 如果你絕對必須總是有一個新的線程,你將不得不創建一個。

+1

我認爲這是正確的答案。我喜歡使用任務的線程抽象,但沒有人可以保證一個新的線程。亨克說,我應該讓它做我想做的事,但這並不能保證一個新的線程。 – Jon

+0

你認爲Henk的評論暗示我在錯誤的軌道上是有效的,如果是的話,我想知道/瞭解更多 – Jon

+0

我認爲混淆是關於像「保證」這樣的詞。 「LongRunning」選項沒有「保證」做任何事情。但是,.NET 4中的默認TaskScheduler確實創建了一個新線程,並且這不太可能會改變。使用任務是一種讓代碼更容易的抽象,但是你確實失去了一些控制。如果它真的對你很重要,那麼你總是可以寫一個TaskScheduler來保證一個新的線程,並且具有兩全其美的優點:) –

3

你必須指定爲什麼你「總是需要一個單獨的線程」。

void Main() 
{ 
    var task = Task.Factory.StartNew(CheckFiles, 
    cancelCheckFile.Token, 
    TaskCreationOptions.LongRunning, 
    TaskScheduler.Default); 

    task.Wait(); 
} 

智能調度程序將在這裏使用1個線程。爲什麼不應該呢?


但是通常CheckFiles()方法會在另一個(比調用)線程上執行。問題是該線程是特別創建的,還是甚至可能在多個線程上執行(連續)。

當您使用任務時,您放棄了對線程的控制。這應該是一件好事。

+0

我想要一個單獨的線程寫入另一個線程上的文件,這樣調用線程就可以完成它想要的任務。我可能需要另一個線程來處理由套接字接收的數據。在這兩種情況下,數據將被添加到一個隊列中,然後在另一個線程上出隊,使得調用線程可以自由地執行其他事情。 – Jon

+0

然後,如果您只允許調度程序執行,那麼調度程序將完全滿足您的需求。 –

+0

但我怎麼能保證。你怎麼知道調度器會在另一個線程上爲我做這件事?另一件我沒有說明,你做的是task.Wait。因爲我想在另一個線程我不等待() – Jon

15

默認任務調度程序ThreadPoolTaskScheduler確實總是爲長時間運行的任務創建一個新線程。它不會像你所看到的那樣使用線程池。這與自己創建線程的手動方法沒有區別。理論上可能發生.NET 4.5的線程調度器做了一些不同的事情,但實際上它不太可能改變。

protected internal override void QueueTask(Task task) 
{  
    if ((task.Options & TaskCreationOptions.LongRunning) != TaskCreationOptions.None) 
    { 
    new Thread(s_longRunningThreadWork) { IsBackground = true }.Start(task); 
    } 
    else 
    { 
    bool forceGlobal = 
     (task.Options & TaskCreationOptions.PreferFairness) != TaskCreationOptions.None; 
    ThreadPool.UnsafeQueueCustomWorkItem(task, forceGlobal); 
    } 
} 
+3

我沒有看到我的答案出了什麼問題。你能否詳細說明你對downvote的推理? –

+3

@Ramhound我意識到這是古老的,但xp!=正確的答案。 Alois是正確的,請參閱「ThreadPoolTask​​Scheduler」的.NET Framework源代碼 - 「QueueTask」的第二種方法:referencesource.microsoft.com/#mscorlib/system/threading/Tasks/ThreadPoolTask​​Scheduler.cs甚至有代碼中的註釋://在自己的專用線程上運行LongRunning任務。 –

8

它取決於您使用的調度程序。有兩個股票實現,ThreadPoolTask​​Scheduler和SynchronizationContextTaskScheduler。後者根本不啓動線程,由FromCurrentSynchronizationContext()方法使用。

ThreadPoolTask​​Scheduler是你得到的。哪個確實使用LongRunning選項,如果設置了它,它將使用常規線程。重要的是要避免捱餓其他TP線程。你會得到一個沒有選項的TP線程。這些實施細節如有更改,恕不另行通知,但我認爲它不太可能。

+0

爲什麼我找不到任何(在線MSDN文章)通過'ThreadPoolTask​​Scheduler站點:msdn.microsoft.com -site:social.msdn.microsoft.com'或通過'SynchronizationContextTaskScheduler站點:msdn.microsoft.com -site:social .msdn.microsoft.com'? –

+1

因爲它們是內部類。正如我提到的「實施細節」。 –

+0

謝謝。請問什麼是「庫存實施」? –