2017-01-23 30 views
0

我更新了一個使用Supersocket連接到舊C++服務器的舊項目。使用最新版本(從0.7.0 => 0.8.0.8),我在嘗試重新連接時遇到了異常(它表示套接字在不同的線程上打開),我希望有一個將任務排入隊列的類(第一個連接和重新連接)並在一個快速的線程上運行它們。編碼任務在特定線程上運行

我見過this方法,但是當我嘗試運行創建爲有一個例外

ExecuteTask may not be called for a task which was previously queued to a different TaskScheduler. 

這裏的任務是我從鏈接採取上述

public class SameThreadTaskScheduler : TaskScheduler, IDisposable 
{ 
    #region publics 
    public SameThreadTaskScheduler(string name) 
    { 
     scheduledTasks = new Queue<Task>(); 
     threadName = name; 
    } 
    public override int MaximumConcurrencyLevel => 1; 

    public void Dispose() 
    { 
     lock (scheduledTasks) 
     { 
      quit = true; 
      Monitor.PulseAll(scheduledTasks); 
     } 
    } 
    #endregion 

    #region protected overrides 
    protected override IEnumerable<System.Threading.Tasks.Task> GetScheduledTasks() 
    { 
     lock (scheduledTasks) 
     { 
      return scheduledTasks.ToList(); 
     } 
    } 

    protected override void QueueTask(Task task) 
    { 
     if (myThread == null) 
      myThread = StartThread(threadName); 
     if (!myThread.IsAlive) 
      throw new ObjectDisposedException("My thread is not alive, so this object has been disposed!"); 
     lock (scheduledTasks) 
     { 
      scheduledTasks.Enqueue(task); 
      Monitor.PulseAll(scheduledTasks); 
     } 
    } 

    public void Queue(Task task) 
    { 
     QueueTask(task); 
    } 


    protected override bool TryExecuteTaskInline(Task task, bool task_was_previously_queued) 
    { 
     return false; 
    } 
    #endregion 

    private readonly Queue<System.Threading.Tasks.Task> scheduledTasks; 
    private Thread myThread; 
    private readonly string threadName; 
    private bool quit; 

    private Thread StartThread(string name) 
    { 
     var t = new Thread(MyThread) { Name = name }; 
     using (var start = new Barrier(2)) 
     { 
      t.Start(start); 
      ReachBarrier(start); 
     } 
     return t; 
    } 
    private void MyThread(object o) 
    { 
     Task tsk; 
     lock (scheduledTasks) 
     { 
      //When reaches the barrier, we know it holds the lock. 
      // 
      //So there is no Pulse call can trigger until 
      //this thread starts to wait for signals. 
      // 
      //It is important not to call StartThread within a lock. 
      //Otherwise, deadlock! 
      ReachBarrier(o as Barrier); 
      tsk = WaitAndDequeueTask(); 
     } 
     for (;;) 
     { 
      if (tsk == null) 
       break; 
      TryExecuteTask(tsk); 
      lock (scheduledTasks) 
      { 
       tsk = WaitAndDequeueTask(); 
      } 
     } 
    } 
    private Task WaitAndDequeueTask() 
    { 
     while (!scheduledTasks.Any() && !quit) 
      Monitor.Wait(scheduledTasks); 
     return quit ? null : scheduledTasks.Dequeue(); 
    } 

    private static void ReachBarrier(Barrier b) 
    { 
     if (b != null) 
      b.SignalAndWait(); 
    } 
} 

這裏是如何的類我打電話給任務

public void RegisterServers() 
    { 

     sameThreadTaskScheduler.Queue(new Task(() => 
      { 
       ...something 
      })); 

什麼在做錯? 謝謝

+0

嘗試在任務調度程序中使用Task.Start(TaskScheduler)或Task.Factory.StartNew,而不是使用此公共的Queue方法。 – acelent

回答

0

您必須開始一個任務,將其綁定到TaskScheduler。在你的代碼中,你手動排隊任務,反過來這樣做,這樣任務就不會被綁定到你的任務調度器(或者任何所有任務),並且TryExecuteTask將會因爲那個錯誤而失敗。描述是相當神祕的,因爲任何實際的TaskScheduler都不同於null

對於您在沒有運行的情況下創建的任務,有Task.RunSynchronouslyTask.Start的重載需要TaskScheduler

對於自動開始運行的任務,有TaskFactory.StartNewTaskFactory<TResult>.StartNew的過載需要TaskScheduler

對於延續的任務,也有Task.ContinueWithTask<TResult>.ContinueWithTaskFactory.ContinueWhenAllTaskFactory.ContinueWhenAny是採取TaskScheduler重載。

不帶任務調度程序的重載等同於指定TaskScheduler.Current。在TaskFactory的情況下,對於默認的Task.Factory,或者在調用工廠方法時沒有任務調度程序的情況下,這是正確的,否則使用工廠的任務調度程序。


對比度與新Task.Run的重載,它總是使用TaskScheduler.Default。根據大多數經驗豐富的人士,線程池調度程序通常比缺省的線程池調度程序要好,它可能是線程綁定的,但爲改變現有API的合同爲時已晚。

相關問題