总是可以使用Task强制新线程吗?

我试图在每次调用Task.Factory.StartNew时创建一个新线程。 问题是如何在不抛出exception的情况下运行代码:

 static void Main(string[] args) { int firstThreadId = 0; Task.Factory.StartNew(() => firstThreadId = Thread.CurrentThread.ManagedThreadId); for (int i = 0; i  { while (true) { Thread.Sleep(1000); if (firstThreadId == Thread.CurrentThread.ManagedThreadId) throw new Exception("The first thread is reused."); } }); } Console.Read(); } 

编辑:新代码,如果你评论第一个语句没有问题。 但是,如果你拥有它,WOW,“Thread reused”消息将被写入控制台。 你能解释一下,因为我真的很困惑。

 static void Main(string[] args) { ConcurrentDictionary startedThreads = new ConcurrentDictionary(); for (int i = 0; i  { Task.Factory.StartNew(() => { startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b); }, TaskCreationOptions.LongRunning); for (int j = 0; j  { while (true) { Thread.Sleep(10); if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused"); } }, TaskCreationOptions.LongRunning); } }); } Console.Read(); } 

如果在启动任务时指定TaskCreationOptions.LongRunning提供调度程序的提示 ,默认调度程序将此提示作为为任务创建新线程的指示符。

这只是一个暗示 – 我不确定我会依赖它……但我没有看到任何使用默认调度程序的反例。

添加Jon Skeet的答案,如果您想保证每次都创建一个新线程,您可以编写自己的TaskScheduler来创建一个新线程。

只需使用新的Thread()启动线程,然后使用Start()启动它们

 static void Main(string[] args) { ConcurrentDictionary startedThreads = new ConcurrentDictionary(); for (int i = 0; i < 10; i++) { new Thread(() => { new Thread(() => { startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b); }).Start(); for (int j = 0; j < 100; j++) { new Thread(() => { while (true) { Thread.Sleep(10); if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused"); } }).Start(); } }).Start(); } Console.Read(); } 

任务应该由调度程序管理。 Tasks的整个想法是运行时将决定何时需要新线程。 另一方面,如果你确实需要不同的线程,那么代码中的其他东西很可能是错误的,例如对Thread.Sleep()或线程本地存储的过度依赖。

正如所指出的,您可以创建自己的TaskScheduler并使用任务来创建线程但是为什么要使用Tasks来开始?

您好,谢谢大家的答案。 你们都得到了+1。 所有建议的解决方案都不适合我的情况。 问题是当你睡眠一个线程时,它会在某个时间点被重用。 以上人士建议:

  • 使用LongRunning =>如果您有嵌套/子任务,这将不起作用
  • 自定义任务调度程序=>我试着写自己的,也试过这个ThreadPerTaskScheduler ,这也不起作用。
  • 使用纯线程=>仍然失败…
  • 你也可以在Multithreading.Scheduler github上查看这个项目

我的解决方案

我不喜欢它,但它有效。 基本上我阻止线程,因此无法重用。 贝娄是扩展方法和工作实例。 再次谢谢你。

https://gist.github.com/4150635

 using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication { public static class ThreadExtensions { ///  /// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool. ///  public static void Block(this Thread thread, int millisecondsTimeout) { new WakeSleepClass(millisecondsTimeout).SleepThread(); } ///  /// Blocks the current thread so that the thread cannot be reused by the threadpool. ///  public static void Block(this Thread thread) { new WakeSleepClass().SleepThread(); } ///  /// Blocks the current thread for a period of time so that the thread cannot be reused by the threadpool. ///  public static void Block(this Thread thread, TimeSpan timeout) { new WakeSleepClass(timeout).SleepThread(); } class WakeSleepClass { bool locked = true; readonly TimerDisposer timerDisposer = new TimerDisposer(); public WakeSleepClass(int sleepTime) { var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime); timerDisposer.InternalTimer = timer; } public WakeSleepClass(TimeSpan sleepTime) { var timer = new Timer(WakeThread, timerDisposer, sleepTime, sleepTime); timerDisposer.InternalTimer = timer; } public WakeSleepClass() { var timer = new Timer(WakeThread, timerDisposer, Timeout.Infinite, Timeout.Infinite); timerDisposer.InternalTimer = timer; } public void SleepThread() { while (locked) lock (timerDisposer) Monitor.Wait(timerDisposer); locked = true; } public void WakeThread(object key) { locked = false; lock (key) Monitor.Pulse(key); ((TimerDisposer)key).InternalTimer.Dispose(); } class TimerDisposer { public Timer InternalTimer { get; set; } } } } class Program { private static readonly Queue tokenSourceQueue = new Queue(); static void Main(string[] args) { CancellationTokenSource tokenSource = new CancellationTokenSource(); tokenSourceQueue.Enqueue(tokenSource); ConcurrentDictionary startedThreads = new ConcurrentDictionary(); for (int i = 0; i < 10; i++) { Thread.Sleep(1000); Task.Factory.StartNew(() => { startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b); for (int j = 0; j < 50; j++) Task.Factory.StartNew(() => startedThreads.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ManagedThreadId, (a, b) => b)); for (int j = 0; j < 50; j++) { Task.Factory.StartNew(() => { while (!tokenSource.Token.IsCancellationRequested) { if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused"); Thread.CurrentThread.Block(10); if (startedThreads.ContainsKey(Thread.CurrentThread.ManagedThreadId)) Console.WriteLine("Thread reused"); } }, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default) .ContinueWith(task => { WriteExceptions(task.Exception); Console.WriteLine("-----------------------------"); }, TaskContinuationOptions.OnlyOnFaulted); } Thread.CurrentThread.Block(); }, tokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default) .ContinueWith(task => { WriteExceptions(task.Exception); Console.WriteLine("-----------------------------"); }, TaskContinuationOptions.OnlyOnFaulted); } Console.Read(); } private static void WriteExceptions(Exception ex) { Console.WriteLine(ex.Message); if (ex.InnerException != null) WriteExceptions(ex.InnerException); } } }