2016-01-22 2 views
2

У меня есть 2 потока, называющих «Task.Factory.StartNew». Давайте просто скажем, что один поток (ThreadA) немного впереди, чем другой (ThreadB).Task.Factory.StartNew гарантированная последовательность выполнения

... в потоке А, вызывается немного вперед

Task.Run(() => { 
    SomeMethodInThreadA(); 
}); 

... в потоке B, немного позже вызывается

Task.Run(() => { 
    SomeMethodInThreadB(); 
}); 

ли TaskScheduler гарантия, что SomeMethodInThreadA запускается на выполнение сначала до SomeMethodInThreadB?

Если нет, то как это сделать? Использовать Task.Factory.StartNew и передать специальный TaskScheduler?

Кроме того, к тому же гарантирует, что SomeMethodInThreadA, обрабатывается первым, я также хочу, чтобы убедиться, что SomeMethodInThreadA заканчивается первый перед выполнением SomeMethodInThreadB.

Я изучил использование StaTaskScheduler, но я не уверен, является ли это решением.

EDIT:

Не давая слишком много деталей/драма о программе я унаследовал, я предполагаю, что я ищу, это обычай TaskScheduler который:

  1. Почести последовательность, когда делегат в очереди

  2. выполняет их последовательно

  3. Делайте это в том же потоке, аналогичный исходному коду StaTaskScheduler, что я связан выше

+0

Не используйте StartNew http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html, если вы действительно не используете другой планировщик (который я, вероятно, не рекомендую) –

+0

Ну, мне нужно, потому что мне как-то нужен специальный TaskScheduler, похожий на то, что пытается сделать StaTaskScheduler. – alpinescrambler

+0

Я чувствую, что вы решаете * неправильную * проблему. –

ответ

3

Не давая слишком много деталей/драма о программе я унаследованной, я предполагаю, что я ищу это обычай TaskScheduler который:

  1. Почести последовательность, когда делегат в очереди

  2. выполняет их последовательно

  3. это сделать в том же потоке, подобно StaTaskScheduler исходный код, который я связан выше

Если это все, что вы хотите, все, что вам нужно сделать, это сделать BlockingCollection<Action> затем цикл по списку на выделенном потоке.

public class BackgroundJobSchedueller 
{ 
    readonly BlockingCollection<Action> _queue; 
    readonly Thread _thread; 

    public BackgroundJobSchedueller() 
    { 
     _queue = new BlockingCollection<Action>() 
     _thread = new Thread(WorkThread) 
     { 
      IsBackground = true, 
      Name = "Background Queue Processor" 
     }; 
     _thread.Start(); 
    } 

    public void StopSchedueller() 
    { 
     //Tell GetConsumingEnumerable() to let the user out of the foreach loop 
     // once the collection is empty. 
     _queue.CompleteAdding(); 

     //Wait for the foreach loop to finish processing. 
     _thread.Join(); 
    } 

    public void QueueJob(Action job) 
    { 
     _queue.Add(job); 
    } 

    void WorkThread() 
    { 
     foreach(var action in _queue.GetConsumingEnumerable()) 
     { 
      try 
      { 
       action(); 
      } 
      catch 
      { 
       //Do something with the exception here 
      } 
     } 
    } 
} 

Когда нет работы, чтобы сделать нить спит, заблокированный на Еогеаспе, как только вы добавить элемент в очередь он получает переработанную затем возвращается в режим сна.

+0

О, дорогая, это работает !, особенно у моих делегатов такая же подпись! – alpinescrambler

+0

Даже если ваши методы не имели такой же знак, вы все равно могли бы использовать его, сокрушив метод в lambada 'schedueller.QueueJob (() => SomeMethodWithParams (42))' –

0

ли гарантия, что TaskScheduler SomeMethodInThreadA запускается на выполнение первых, прежде чем SomeMethodInThreadB?

No.

Если нет, то как я могу это сделать?

у вас вторая задача является продолжением вашей первой задачи с помощью ContinueWith

Что-то вроде:

var task = Task.Run(() => { 
    SomeMethodInThreadA(); 
}); 

потом:

task.ContinueWith(t => { 
    SomeOtherMethodInThreadA(); 
}); 
+0

Эти два потока не обязательно общаются друг с другом, поэтому мне не удастся завладеть этой переменной «задача». – alpinescrambler

+0

@alpinescrambler: Конечно, вы можете. Плюс он существует в родительском потоке не в потоке A. –

+0

То, что я имею в виду, эти 2 потока написаны так, что они независимы друг от друга. Невозможно передать переменную «задача», которую вы захватили в своем примере. – alpinescrambler

0
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Task.Factory.StartNew(() => MethodA()) 
       .ContinueWith(a => 
       { 
        MethodB(); 
       }); 

      Console.WriteLine("Press a key to exit"); 
      Console.ReadKey(false); 

     } 

     public static void MethodA() 
     { 
      Thread.Sleep(2000); 
      Console.WriteLine("Hello From method A {0}", Thread.CurrentThread.ManagedThreadId); 
     } 

     public static void MethodB() 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("Hello From method B {0}", Thread.CurrentThread.ManagedThreadId); 
     } 
    } 
} 
0

Does T он TaskScheduler гарантирует, что SomeMethodInThreadA получает , выполненный раньше, чем SomeMethodInThreadB?

Конечно, нет.

Если нет, то как это сделать?

Если 2 нити полностью независимы друг от друга, и все же SomeMethodInThreadB должны выполняться после того, как SomeMethodInThreadA закончил вы можете использовать стандартные процедуры синхронизации потоков:

public static AutoResetEvent Wait = new AutoResetEvent(false); 

, а затем при запуске первой задачи:

var task = Task.Run(() => 
{ 
    // Sets the state of the event to nonsignaled, causing threads to block. 
    Wait.Reset(); 

    // Execute the first task 
    SomeMethodInThreadA(); 

    // The first task has finished executing -> signal the second 
    // thread which is probably waiting that it can start processing 
    // the second task 
    Wait.Set(); 
}); 

, а затем во втором потоке ожидают сообщения о завершении первого метода:

Task.Run(() => 
{ 
    if (!Wait.WaitOne(TimeSpan.FromMinutes(30))) 
    { 
     // We have waited for too long the first task to execute - giving up 
    } 
    else 
    { 
     // The first task has finished executing - we can now 
     // proceed with the second task 
     SomeMethodInThreadB(); 
    } 
}); 

Очевидно, вам решать, как долго второй поток будет ждать завершения первой задачи, прежде чем сдаться.

Смежные вопросы