2013-09-25 37 views
0

我写了我的自定义的TaskScheduler:为什么在主线程中运行任务?

public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler 
{ 

    private BlockingCollection<Task> _tasks = new BlockingCollection<Task>(); 
    private List<Thread> _threads; 
    private bool work = true; 

    public LimitedConcurrencyLevelTaskScheduler(int maxConcurrencyLevel) 
    { 

     _threads = new List<Thread>(); 
     for (int i = 0; i < maxConcurrencyLevel; i++) 
     { 
      _threads.Add(new Thread(() => 
             { 
              while (work) 
              { 
               TryExecuteTask(_tasks.Take()); 
              } 
             }) { IsBackground = true, Name = "TaskShedulerThread#" + i }); 
     } 
     foreach (var thread in _threads) 
     { 
      thread.Start(); 
     } 

    } 

    protected override void QueueTask(Task task) 
    { 
     _tasks.Add(task); 
    } 

    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
    { 
     return !_threads.Contains(Thread.CurrentThread) && TryExecuteTask(task); 
    } 

    public override int MaximumConcurrencyLevel { get { return 1; } } 

    protected override IEnumerable<Task> GetScheduledTasks() 
    { 
     return _tasks.ToArray(); 
    } 

    public void Dispose() 
    { 
     if (_threads != null) 
     { 
      _tasks.CompleteAdding(); 
      work = false; 

      _tasks.Dispose(); 
      _tasks = null; 
      _threads = null; 
     } 
    } 
} 

并以这种方式使用它:

static void Main(string[] args) 
    { 
     var taskScheduller = new LimitedConcurrencyLevelTaskScheduler(1); 
     Thread.CurrentThread.Name = "MainThread"; 
     var taskFactory = new TaskFactory(taskScheduller); 
     var tasks = new Task[100]; 
     for (int i = 0; i < 100; i++) 
     { 
      tasks[i] = taskFactory.StartNew(() => Console.WriteLine(String.Format("Call in {0}", Thread.CurrentThread.Name))); 
     } 
     Task.WaitAll(tasks); 
    } 

PROGRAMM的输出:

Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in MainThread 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in MainThread 
Call in MainThread 
Call in MainThread 
Call in MainThread 
Call in MainThread 
Call in MainThread 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
Call in TaskShedulerThread#0 
... 

为什么我的任务在主线程拼命地跑?

回答

0

由于称为task inlining的TPL功能,任务正在主线程上执行。当线程在尚未开始执行的任务上调用WaitAll(或任何类似的方法)时,TPL可允许所述线程自己尝试执行待定任务,而不是阻塞,直到其由任务调度程序的工作人员之一执行线程。

可以通过覆盖任务调度器的TryExecuteTaskInline方法来控制此行为,禁止它执行任何任务,除非当前线程碰巧是工作线程。

protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
{ 
    return !_threads.Contains(Thread.CurrentThread) && TryExecuteTask(task); 
} 

在您的实现,您只需要Contains检查之前删除的否定:

protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) 
{ 
    return _threads.Contains(Thread.CurrentThread) && TryExecuteTask(task); 
} 
相关问题