Как гарантировать создание нового потока при использовании метода Task.StartNew - PullRequest
13 голосов
/ 07 ноября 2011

Из того, что я могу сказать, у меня есть вводящие в заблуждение биты информации. Мне нужно, чтобы в фоновом режиме работал отдельный поток.

На данный момент я делаю это так:

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
   }
}

Вы бы порекомендовали мне вернуться к этому подходу, чтобы гарантировать, что используется новый поток?

Ответы [ 4 ]

16 голосов
/ 07 ноября 2011

Планировщик задач по умолчанию 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);
  }
}
8 голосов
/ 07 ноября 2011

Это зависит от используемого вами Планировщика.Существует две стандартные реализации: ThreadPoolTaskScheduler и SynchronizationContextTaskScheduler.Последний вообще не запускает поток, используемый методом FromCurrentSynchronizationContext ().

ThreadPoolTaskScheduler - это то, что вы получаете.Который действительно использует параметр LongRunning, он будет использовать обычный поток, если он установлен.Важно избегать голодания по другим нитям TP.Вы получите поток TP без опции.Эти детали реализации могут быть изменены без предварительного уведомления, хотя я считаю, что это вряд ли произойдет в ближайшее время.

5 голосов
/ 08 ноября 2011

LongRunning - это всего лишь подсказка для планировщика - если вам абсолютно необходимо всегда иметь новый поток, вам придется его создать.

4 голосов
/ 07 ноября 2011

Вам нужно будет указать , почему вам "всегда нужен отдельный поток".

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

   task.Wait();
}

Умный планировщик будет использовать 1 поток здесь.Почему бы и нет?


Но в целом метод CheckFiles () будет выполняться в другом (не вызывающем) потоке.Вопрос заключается в том, создан ли этот поток специально или он может даже выполняться в нескольких потоках (последовательно).

Когда вы используете Задачи, вы отказываетесь от управления потоком.И это должно быть хорошо.

...