2

I have windows service that can get requests, I want to handle in each request in separated thread.

I want to limit also the number of the threads, i.e maximum 5 threads.

And i want to wait for all threads before i'm close the application,

What is the best way to do that?

What I'm tried:

 for (int i = 0; i < 10; i++)
        {
            var i1 = i;
            Task.Factory.StartNew(() => RequestHandle(i1.ToString())).ContinueWith(t => Console.WriteLine("Done")); 

        }
        Task.WaitAll();//Not waiting actually for all threads, why?

In this way i can limit the number of the theads?

Or

var events = new ManualResetEvent[10];

         ThreadPool.SetMaxThreads(5, 5);
         for (int i = 0; i < 10; i++)
         {
             var i1 = i;
             ThreadPool.QueueUserWorkItem(x =>
             {
                 Test(i1.ToString());
                 events[i1].Set();
             });
         }

         WaitHandle.WaitAll(events);

There is another way to implement that?

CSharpBeginner
  • 601
  • 2
  • 7
  • 22
  • How do you "get requests"? That kind of matters. It's not so clear you should be using the pool. And SetMaxThreads() is app-global, you are preventing the threads to spin off helpers threads. – H H Feb 23 '17 at 08:55
  • *As soon as you type `new Thread()`, it's over; your project already has legacy code.* Concurrency in C# Cookbook, @StephenCleary - which also applies to the `ThreadPool` –  Feb 23 '17 at 08:56
  • http://stackoverflow.com/questions/9315937/net-tpl-limited-concurrency-level-task-scheduler-with-task-priority, https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.maximumconcurrencylevel, ... –  Feb 23 '17 at 08:57

2 Answers2

2

Both approaches should work, neither is a guarantee that each operation will run in a different thread (and that is a good thing). Controlling the maximun number of threads is another thing...

You can set the maximun number of threads of the ThreadPool with SetMaxThreads. Remember that this change is global, you only have one ThreadPool.

The default TaskScheduler will use the thread pool (except in some particular situations where it can run the taks inline on the same thread that is calling them), so changing the parameters of the ThreadPool will also affect the Tasks.

Now, notice I said default TaskScheduler. You can roll your own, which will give you more control over how the tasks will run. It is not advised to create a custom TaskScheduler (unless you really need it and you know what you are doing).


For the embedded question:

Task.WaitAll();//Not waiting actually for all threads, why?

To correctly call Task.WaitAll you need to pass the tasks you want to wait for as parameters. There is no way to wait for all currently existing tasks implicitly, you need to tell it what tasks you want to wait for.

Theraot
  • 31,890
  • 5
  • 57
  • 86
  • `ThreadPool.SetMaxThreads` has some limitations (the number is bound to the amount of cores, IIS may overwrite the values, ...) - [SmartThreadPool](https://github.com/amibar/SmartThreadPool) might be the better option. –  Feb 23 '17 at 09:00
1

Task.WaitAll();//Not waiting actually for all threads, why? you have to the following

 List<Task> tasks =  new List<Task>(); 
 for (int i = 0; i < 10; i++)
        {

            var i1 = i;
          tasks.Add(Task.Factory.StartNew(() => RequestHandle(i1.ToString())).ContinueWith(t => Console.WriteLine("Done"))); 

        }
    Task.WaitAll(tasks);

I think that you should make the differences between Task and thread

Task are not threads Task is just a promise of result in the future and your code can execute on only one thread even if you have many tasks scheduled

Thread is a low-level concept if you start a thread you know that it will be a separate thread I think you first implentation is well enough to be sure that all your code is executed but you have to use Task.Run instead of Task.Factory.StartNew

BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47