10

I'm trying to get a list of all currently running tasks. Does the .net 4.0 tasks api provide such functionality? Or the only option is explicitly to store tasks in a separate collection?

Stephan Bauer
  • 9,120
  • 5
  • 36
  • 58
Markus
  • 3,547
  • 10
  • 39
  • 55
  • possible duplicate of [C# - Get list of open tasks](http://stackoverflow.com/questions/310456/c-sharp-get-list-of-open-tasks) – Shai May 31 '12 at 08:19
  • 2
    I meant through TaskFactory or TaskScheduler objects. – Markus May 31 '12 at 08:23
  • Why would you need that and what do you mean by "running"? There may be multiple tasks scheduled at any time but only a few of them will be assigned to threads and running. Are you looking for the scheduled tasks or those that are actually running? – Panagiotis Kanavos Jun 01 '12 at 07:17

5 Answers5

5

I suppose you need TaskScheduler.GetScheduledTasks method, but:

  1. It's protected
  2. MSDN says it should be used only for debugging
  3. As far as I know this method has implemented only by ThreadPoolTaskScheduler, SynchronizationContextTaskScheduler always returns null

So I think you should try to implement own TaskScheduler to achieve your goals.

Rusted
  • 579
  • 3
  • 9
  • GetScheduledTasks is an abstract method so all TaskScheduler-derived classes have to implement it – Panagiotis Kanavos Jun 01 '12 at 07:21
  • ***own TaskScheduler*** _real world sample_ ? – Kiquenet May 16 '18 at 07:26
  • @Kiquenet why would you want to do that? Besides, there are a lot of examples already, including examples in the documentation of [TaskScheduler itself](https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx). If you have an issue with your code though, creating a new TaskScheduler will only make it worse – Panagiotis Kanavos May 16 '18 at 07:30
  • I use ***Task Scheduler*** in Windows, I want get state of my tasks – Kiquenet May 17 '18 at 07:05
  • @PanagiotisKanavos In my application I have thousands of incoming MQTT messages that have to be transformed to output XML messages. I use 2 custom TaskScheduler (from Microsoft sample). They use the ThreadPool... but will not flood the ThreadPool with all these Tasks, this let me the possibility to quickly handle simple things like Timers (executed on ThreadPool). Otherwise, I have to wait to ThreadPool dequeues a lot a work prior to handling my Timer_Elapsed. So creating a own ThreadPool could be a really good solution. – Elo Jan 21 '20 at 14:41
  • @Elo no it won't. This question was posted back in early 2012 about .NET 4.0. The TPL Dataflow library introduced later that year with 4.5 makes queued processing almost trivial - create an ActionBlock with a DOP of whatever you want and start posting messages to it. Set a buffer limit to provide backpressure. Lately, Channels provide a similar but lower-level abstraction for pub/sub and pipelines – Panagiotis Kanavos Jan 21 '20 at 14:46
  • "No it won't" lol you are so peremptory @PanagiotisKanavos ! Nevertheless, thanks for System.Threading.Tasks.Dataflow, could be useful for reception. I also need to async publish packets with Tasks, and I found a really good solution implementing a custom TaskScheduler. This allows me to work with Tasks and protect the ThreadPool from flooding. – Elo Jan 21 '20 at 15:01
2

When you create a Task, by default the task is scheduled to run on a thread pool thread. So, you can get number of running tasks by using ThreadPool.GetMaxThreads and ThreadPool.GetAvailableThreads methods.

    private static int GetWorkingThreads() {
        int maxThreads;
        int completionPortThreads;
        ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);

        int availableThreads;
        ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);

        return maxThreads - availableThreads;
    }
Unril
  • 106
  • 1
  • 3
2

@HelgeJensen proposed a working solution on : How can I monitor the Task queues in the .NET TaskSchedulers (across AppDomain)

Microsoft discourage the use of GetScheduledTasksForDebugger Method :

This method is not thread safe and you shouldn't use it concurrently with other instances of TaskScheduler. Call this method from a debugger only when the debugger has suspended all other threads.

I tested the proposed solution and it works, even if we would likely encounter crashes using that in production code :

public static class ScheduledTaskAccess
{
    public static Task[] GetScheduledTasksForDebugger(TaskScheduler ts)
    {
        var mi = ts.GetType().GetMethod("GetScheduledTasksForDebugger", BindingFlags.NonPublic | BindingFlags.Instance);
        if (mi == null)
            return null;
        return (Task[])mi.Invoke(ts, new object[0]);
    }      
}

Usage:

    Task[] tasks = GetScheduledTasksForDebugger(TaskScheduler.Current);
    int count = tasks.Length;

And we could see the Status of each Task: Obtained list of Tasks

Elo
  • 2,234
  • 22
  • 28
1

Why would you want to find the list of running tasks? Apart from debugging, you shouldn't have to use this information. In any case, there is a difference between the list of the tasks that are scheduled for execution and the tasks that are actually executing.

As Rusted writes, you can get the number of scheduled tasks from the TaskScheduler.GetScheduledTasks method. The method is abstract so it has to be implemented by all TaskSchedulers.

How many tasks actually execute depends on the TaskScheduler implementation. The default task scheduler uses the threadpool, in which case you should check ThreadPool.GetAvailableThreads and ThreadPool.GetMaxThreads to approximate the number of executing tasks.

There is no actual list of running tasks, even when you use the default TaskScheduler. The scheduler essentially assigns a task to a ThreadPool and leaves the actual execution to the pool (actually, it calls the Task.ExecuteEntry private method). It has no need to keep a list of the running tasks.

If you want the running task information for debugging purposes, you can take advantage of the Event Trace for Windows events in TPL. Unfortunately, the Task Started and Task Finished events are not documented. I found them while browsing the definition of Task.ExecuteEntry with dotPeek.

I've found one article exploring the TPL events but I'm not sure it's worth the trouble. Unless you are writing your own debugger, it seems too much trouble.

If you just have to get to the list of running tasks, perhaps you should write your own TaskScheduler and override TryExecute and TryExecuteInternal to intercept the execution of each task and place each task in a list. This could get expensive though, and you would have to do some cleanup periodically to remove completed tasks from the list without using continuations (which would end up in the list themselves).

Nick Westgate
  • 3,088
  • 2
  • 34
  • 41
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • https://naveensrinivasan.com/2010/03/30/exploring-event-tracing-for-windows-etw-within-task-parallel-library-tpl-using-perfmonitor/ not found – Kiquenet May 16 '18 at 07:24
  • @Kiquenet one more reason this isn't worth it. Why do you care? If you have an issue it's almost certainly not related to the list of executing or scheduled tasks. Post a question with the actual problem. – Panagiotis Kanavos May 16 '18 at 07:28
  • @PanagiotisKanavos Even if there is no list of Running Tasks, each Task has a "Status" property to know if it is running. The GetScheduledTasks() method is protected and cannot be accessed from .NET The reason of accessing the list of Tasks could be to know system health (let's say you see hundreds of waiting Tasks) or do some "snapshots" during production to see if Tasks order is consistent : if you have TaskA x 100 and then TaskB x 100, it could show a problem when you expect TaskA, TaskB, TaskA, TaskB... – Elo Jan 21 '20 at 14:45
0

There is a good article on the MSDN http://msdn.microsoft.com/en-us/library/ms997649.aspx Everything you need is described very well.

Edit: perhabs this will help:

using System;
using System.Diagnostics;

class MainClass
{
   public static void Main()
   {
      Process[] allProcs = Process.GetProcesses();

      foreach(Process proc in allProcs)
      {
         ProcessThreadCollection myThreads = proc.Threads;
         Console.WriteLine("process: {0},  id: {1}", proc.ProcessName, proc.Id);

         foreach(ProcessThread pt in myThreads)
         {
            Console.WriteLine("  thread:  {0}", pt.Id);
            Console.WriteLine("    started: {0}", pt.StartTime.ToString());
            Console.WriteLine("    CPU time: {0}", pt.TotalProcessorTime);
            Console.WriteLine("    priority: {0}", pt.BasePriority);
            Console.WriteLine("    thread state: {0}", pt.ThreadState.ToString()); 
         }
      }
   }
}
HW90
  • 1,953
  • 2
  • 21
  • 45