C# 如何保证在使用Task.StartNew方法时创建新线程
据我所知,我有一些误导性的信息。我需要有一个单独的线程在后台运行 目前我是这样做的:C# 如何保证在使用Task.StartNew方法时创建新线程,c#,.net,multithreading,.net-4.0,task-parallel-library,C#,.net,Multithreading,.net 4.0,Task Parallel Library,据我所知,我有一些误导性的信息。我需要有一个单独的线程在后台运行 目前我是这样做的: var task = Task.Factory.StartNew (CheckFiles , cancelCheckFile.Token , TaskCreationOptions.LongRunning , TaskScheduler.Default);//Check for files on another thread pr
var task = Task.Factory.StartNew
(CheckFiles
, cancelCheckFile.Token
, TaskCreationOptions.LongRunning
, TaskScheduler.Default);//Check for files on another thread
private void CheckFiles()
{
while (!cancelCheckFile.Token.IsCancellationRequested)
{
//do stuff
}
}
thQueueChecker = new Thread(new ThreadStart(CheckQueue));
thQueueChecker.IsBackground = true;
thQueueChecker.Name = "CheckQueues" + DateTime.Now.Ticks.ToString();
thQueueChecker.Start();
private void CheckQueue()
{
while (!ProgramEnding)
{
//do stuff
}
}
这总是为我创建一个新的线程。然而,经过多次讨论后,即使它被标记为LongRunning,也不能保证会创建一个新线程
过去我做过这样的事情:
var task = Task.Factory.StartNew
(CheckFiles
, cancelCheckFile.Token
, TaskCreationOptions.LongRunning
, TaskScheduler.Default);//Check for files on another thread
private void CheckFiles()
{
while (!cancelCheckFile.Token.IsCancellationRequested)
{
//do stuff
}
}
thQueueChecker = new Thread(new ThreadStart(CheckQueue));
thQueueChecker.IsBackground = true;
thQueueChecker.Name = "CheckQueues" + DateTime.Now.Ticks.ToString();
thQueueChecker.Start();
private void CheckQueue()
{
while (!ProgramEnding)
{
//do stuff
}
}
您是否建议我回到这种方法以保证使用新线程?您必须指定为什么“始终需要单独的线程”
智能调度程序将在此处使用1个线程。为什么不应该呢
但通常,CheckFiles()方法将在另一个(而不是调用)线程上执行。问题在于该线程是否是专门创建的,或者它是否可能(连续)在多个线程上执行
当您使用任务时,您放弃了对线程的控制。这应该是件好事 默认任务调度程序
ThreadPoolTaskScheduler
确实总是为长时间运行的任务创建新线程。正如您所看到的,它不使用线程池。这与手动创建线程没有什么不同。从理论上讲,.NET4.5的线程调度程序可能会做一些不同的事情,但实际上它不太可能改变
protected internal override void QueueTask(Task task)
{
if ((task.Options & TaskCreationOptions.LongRunning) != TaskCreationOptions.None)
{
new Thread(s_longRunningThreadWork) { IsBackground = true }.Start(task);
}
else
{
bool forceGlobal =
(task.Options & TaskCreationOptions.PreferFairness) != TaskCreationOptions.None;
ThreadPool.UnsafeQueueCustomWorkItem(task, forceGlobal);
}
}
这取决于您使用的调度程序。有两种常用实现,ThreadPoolTaskScheduler和SynchronizationContextTaskScheduler。后者根本不启动由FromCurrentSynchronizationContext()方法使用的线程
ThreadPoolTaskScheduler就是您得到的。它确实使用了LongRunning选项,如果设置了,它将使用常规线程。重要的是要避免饥饿其他TP线程。您将获得一个没有该选项的TP线程。这些是实现细节,如有变更,恕不另行通知,虽然我认为它不太可能很快。 < P> LongRunning只是对调度器的暗示——如果您必须始终有一个新线程,您必须创建一个。我需要一个单独的线程写入另一个线程上的文件,以便让调用线程执行它想要的操作。我可能需要另一个线程来处理套接字接收的数据。在这两种情况下,数据都将添加到队列中,然后在另一个线程上退出队列,让调用线程自由地执行其他操作。如果您只允许,调度程序将完全执行您需要的操作。但我如何保证这一点。你怎么知道调度程序会在另一个线程上为我这样做?还有一件事我没有具体说明,而你要做的就是任务。等等。因为我想在另一个线程上使用它,所以我不等待()@Jon-你还没有解释为什么你“需要一个新线程”。它和“一条单独的线”混淆了。无论如何,您现在走错了方向。当您需要保证另一个线程时的示例:您从
SetWindowsHookEx
获得回调,并且您需要执行COM调用,例如WMI API。如果在回调中执行此操作,则会出现一个异常:由于应用程序正在发送输入同步调用,因此无法进行传出调用。你必须保证在一个单独的线程上运行你需要的任何东西。longlunning
只是对调度程序的一个提示-如果你一定要一直有一个新线程,你就必须创建一个。想把它作为一个答案吗?我想一个常见的困惑点是答案中没有答案的地址,它不能保证生成一个新线程,但它将始终使用线程池中的线程,它可能只是重用池中空闲的线程,而不做任何工作。如果您从非线程池线程调用Task.Factory.StartNew
,它将始终在不同的线程上运行代码,您只是不知道该线程是全新的,还是以前用于运行其他代码。我看不出我的回答有什么问题。你能详细解释一下你为什么要投否决票吗?@Ramhound我知道这很古老,但是xp!=回答正确。阿洛伊斯是对的,请参阅.NET Framework sourcecode以了解ThreadPoolTaskScheduler
-第二种方法downQueueTask
:referencesource.microsoft.com/#mscorlib/system/threading/Tasks/ThreadPoolTaskScheduler.cs甚至在代码中有一条注释://在自己的专用线程上运行LongRunning任务。我认为这是正确的答案。我喜欢使用Task抽象线程,但没有人能保证有一个新线程。Henk说我应该让它做我想做的,但这并不保证会有一个新的线程。你认为Henk说我走错了方向是正确的吗?如果是的话,我想知道/了解更多。我想混淆的是像“保证”这样的词。LongRunning
选项根本不能“保证”做任何事情。然而,.NET4中的默认TaskScheduler确实创建了一个新线程,这不太可能改变。使用任务是一种使代码更容易的抽象,但是您确实会失去一些控制。如果这对你真的很重要,那么你可以编写一个TaskScheduler来保证一个新的线程,并兼得这两个方面的优点:)有趣的想法。我在创建和管理线程方面没有问题,我只是认为现在的重点是让TPL为您做这件事,但如果它不能保证新线程,那么您的选择/答案会更好。我也不确定Henk所说的独立线程和新线程之间的区别是什么意思。当然,这是一样的,除非有一个神奇的隐藏线程等着我发布命令让它去做。正如你已经发现的,这里确实有“神奇的”隐藏线程。但真正的问题是,你为什么要保证它将如何执行?如果任务调度器有理由相信可能不需要新线程,那么为什么您会认为您知道得更好?这样的决定背后有很多理论和权衡。为什么我找不到(在线)呢