How to get a list of running threads in C #?

I am creating dynamic threads in C # and I need to get the status of these running threads.

List<string>[] list; list = dbConnect.Select(); for (int i = 0; i < list[0].Count; i++) { Thread th = new Thread(() =>{ sendMessage(list[0]['1']); //calling callback function }); th.Name = "SID"+i; th.Start(); } for (int i = 0; i < list[0].Count; i++) { // here how can i get list of running thread here. } 

How can you get a list of running threads?

+5
source share
5 answers

Create a List<Thread> and save each new thread in your first for loop.

 List<string>[] list; List<Thread> threads = new List<Thread>(); list = dbConnect.Select(); for (int i = 0; i < list[0].Count; i++) { Thread th = new Thread(() =>{ sendMessage(list[0]['1']); //calling callback function }); th.Name = "SID"+i; th.Start(); threads.add(th) } for (int i = 0; i < list[0].Count; i++) { threads[i].DoStuff() } 

However, if you do not need i , you can make a second loop a foreach instead of for


As a side note, if your sendMessage function sendMessage not take a very long time, you should have a lighter weight and then a full thread, use ThreadPool. QueueUserWorkItem or if it is available to you, Task

+7
source

In streams

I would not explicitly create threads myself.

It is much more preferable to use ThreadPool.QueueUserWorkItem , or if you can use .Net 4.0, you will get a much more powerful Task parallel library , which also allows you to use ThreadPool threads in a much more powerful way ( Task.Factory.StartNew worth a look)

What if we decide to move on to direct thread creation?

Suppose your list is [0] .Count returns 1000 items. Suppose also that you are doing this on a high-end (as of this writing) 16core machine. The immediate effect is that we have 1000 threads competing for these limited resources (16 cores).

The larger the number of tasks and the more each of them is completed, the more time will be spent switching contexts . In addition, creating threads is expensive, these overheads that create each thread can clearly be avoided if you take the approach of reusing existing threads.

Thus, although the initial intention of multithreading may be to increase the speed, as we can see, this can have the exact opposite effect.

How do we overcome "excessive" threads?

It uses ThreadPool .

A thread pool is a collection of threads that can be used to perform a number of tasks in the background.

How do they work:

Once the thread in the pool completes its task, it returns to the waiting thread queue, where it can be reused. This reuse allows applications to avoid the cost of creating a new thread for each task.

Thread pools usually have the maximum number of threads. If all threads are busy, additional tasks are queued until they can be serviced as threads become available.

Thus, we see that using thread pool threads we are more efficient as

  • in terms of maximizing actual work . Since we do not overload processors with threads, less time is spent switching between threads and more time actually executing the code that the thread should execute.
  • Faster start of the stream : each stream stream is easily accessible, and does not wait until a new stream is created.
  • in terms of minimizing memory consumption , threadpool will limit the number of threads to the size of threadpool, depending on any requests that go beyond the threadpool thread limit. (see ThreadPool.GetMaxThreads ). The main reason for this design choice, of course, is that we do not oversaturate a limited number of cores with too many thread requests, while keeping the context moving to lower levels.

Too many Theories, let's test this whole theory!

That's right, it’s good to know all this in theory, but let's practice and see what the numbers tell us, with a simplified rough version of the application that can give us a rough indication of the difference in orders of magnitude. We will make a comparison between the new Thread, ThreadPool and the parallel task library (TPL)

new topic

  static void Main(string[] args) { int itemCount = 1000; Stopwatch stopwatch = new Stopwatch(); long initialMemoryFootPrint = GC.GetTotalMemory(true); stopwatch.Start(); for (int i = 0; i < itemCount; i++) { int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable. Thread thread = new Thread(() => { // lets simulate something that takes a while int k = 0; while (true) { if (k++ > 100000) break; } if ((iCopy + 1) % 200 == 0) // By the way, what does your sendMessage(list[0]['1']); mean? what is this '1'? if it is i you are not thread safe. Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds); }); thread.Name = "SID" + iCopy; // you can also use i here. thread.Start(); } Console.ReadKey(); Console.WriteLine(GC.GetTotalMemory(false) - initialMemoryFootPrint); Console.ReadKey(); } 

Result:

New thread benchmark

ThreadPool.EnqueueUserWorkItem

  static void Main(string[] args) { int itemCount = 1000; Stopwatch stopwatch = new Stopwatch(); long initialMemoryFootPrint = GC.GetTotalMemory(true); stopwatch.Start(); for (int i = 0; i < itemCount; i++) { int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable. ThreadPool.QueueUserWorkItem((w) => { // lets simulate something that takes a while int k = 0; while (true) { if (k++ > 100000) break; } if ((iCopy + 1) % 200 == 0) Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds); }); } Console.ReadKey(); Console.WriteLine("Memory usage: " + (GC.GetTotalMemory(false) - initialMemoryFootPrint)); Console.ReadKey(); } 

Result:

Threadpool benchmark

Parallel Task Library (TPL)

  static void Main(string[] args) { int itemCount = 1000; Stopwatch stopwatch = new Stopwatch(); long initialMemoryFootPrint = GC.GetTotalMemory(true); stopwatch.Start(); for (int i = 0; i < itemCount; i++) { int iCopy = i; // You should not use 'i' directly in the thread start as it creates a closure over a changing value which is not thread safe. You should create a copy that will be used for that specific variable. Task.Factory.StartNew(() => { // lets simulate something that takes a while int k = 0; while (true) { if (k++ > 100000) break; } if ((iCopy + 1) % 200 == 0) // By the way, what does your sendMessage(list[0]['1']); mean? what is this '1'? if it is i you are not thread safe. Console.WriteLine(iCopy + " - Time elapsed: (ms)" + stopwatch.ElapsedMilliseconds); }); } Console.ReadKey(); Console.WriteLine("Memory usage: " + (GC.GetTotalMemory(false) - initialMemoryFootPrint)); Console.ReadKey(); } 

Result:

Task parallel library result

So we can see that:

 +--------+------------+------------+--------+ | | new Thread | ThreadPool | TPL | +--------+------------+------------+--------+ | Time | 6749 | 228ms | 222ms | | Memory | β‰ˆ300kb | β‰ˆ103kb | β‰ˆ123kb | +--------+------------+------------+--------+ 

The above goes well with what we expected in theory. High memory for the new topic, as well as lower overall performance compared to ThreadPool. ThreadPool and TPL have equivalent performance, with TPL having a slightly higher amount of memory than a pure thread pool, but it may be worth the cost for additional flexibility. Tasks provide (for example, cancellation, waiting for the completion of a request to complete a task).

At this point, we proved that using ThreadPool threads is the preferred option in terms of speed and memory.

However, we did not answer your question. How to track the status of running threads.

To answer your question

Given the ideas we got, here's how I approach him:

  List<string>[] list = listdbConnect.Select() int itemCount = list[0].Count; Task[] tasks = new Task[itemCount]; stopwatch.Start(); for (int i = 0; i < itemCount; i++) { tasks[i] = Task.Factory.StartNew(() => { // NOTE: Do not use i in here as it is not thread safe to do so! sendMessage(list[0]['1']); //calling callback function }); } // if required you can wait for all tasks to complete Task.WaitAll(tasks); // or for any task you can check its state with properties such as: tasks[1].IsCanceled tasks[1].IsCompleted tasks[1].IsFaulted tasks[1].Status 

As a last note, you cannot use the variable i in your Thread.Start, since it will create a variable closure that will be used effectively for all threads. To get around this (assuming you need to access i), just create a copy of the variable and pass it in, it will make one short circuit to the thread, which will make it thread safe.

Good luck

+35
source

Use Process.Threads :

 var currentProcess = Process.GetCurrentProcess(); var threads = currentProcess.Threads; 

Note: all threads belonging to the current process will be displayed here, including those that are not explicitly created by you.

If you only need the threads that you created, then why don't you just keep track of them when you create them?

+9
source
 Process.GetCurrentProcess().Threads 

This gives you a list of all threads running in the current process, but be careful that there are topics other than those you started yourself.

+1
source

Use Process.Threads to repeat your threads.

0
source

Source: https://habr.com/ru/post/910013/


All Articles