2016-01-22 137 views
2

我有2個線程調用「Task.Factory.StartNew」。我們只要說一個線程(ThreadA)比另一個線程(ThreadB)略高一點。Task.Factory.StartNew保證執行順序

...在線程A,稍微提前調用

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

...在線程B,後來

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

是否的TaskScheduler保證SomeMethodInThreadA被執行略有調用首先在SomeMethodInThreadB

如果不是,我該怎麼做?使用Task.Factory.StartNew並傳入特殊的TaskScheduler?

此外,除了低保SomeMethodInThreadA首先得到處理,我也想先執行SomeMethodInThreadB前確保SomeMethodInThreadA完成。

我已經看過使用StaTaskScheduler,但我不確定這是否是解決方案。

編輯:

,不會產生約我繼承的程序太多細節/電視劇,我想我在找的是一個自定義的TaskScheduler其中:

  1. 榮譽序列時該委託被排隊

  2. 執行它們串聯

  3. 做在同一個線程,類似於我上面

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

當沒有工作可做線程睡眠,阻塞在foreach,一旦你添加項目到它被處理的隊列,然後返回休眠。

+0

哦親愛的,這個作品!特別是我的代表有相同的簽名! – alpinescrambler

+0

即使你的方法沒有相同的符號,你仍然可以通過在lambda'schedueller.QueueJob(()=> SomeMethodWithParams(42))中包裝該方法來使用它。 –

0

鏈接的StaTaskScheduler源代碼是否的TaskScheduler保證SomeMethodInThreadA首先得到SomeMethodInThreadB之前執行?

如果沒有,我該怎麼辦呢?

有你第二個任務是你的第一個任務的延續使用ContinueWith

喜歡的東西:

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

再後來:

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

2個線程不一定相互通信,所以我無法掌握該「任務」變量。 – alpinescrambler

+0

@alpinescrambler:當然可以。加上它存在於父線程而不是線程A中。 –

+0

我的意思是,這兩個線程被寫成使得它們彼此獨立。沒有工具可以傳遞您在示例中捕獲的「任務」變量。 – 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

不Ť他的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(); 
    } 
}); 

顯然,您需要定義第二個線程在放棄之前等待第一個任務完成的時間。