Share via


Create multiple threads within console app

Question

Tuesday, August 4, 2020 9:58 PM

Hi everyone,

I tried to call 10 threads within a console app, but it is only running 7 threads!!

What I am doing wrong?

  class Program
    {
        static void Main(string[] args)
        {
            Thread CallTask1 = new Thread(Task1);
            CallTask1.Start();

            Thread CallTask2 = new Thread(Task2);
            CallTask2.Start();

            Thread CallTask3 = new Thread(Task3);
            CallTask3.Start();

            Thread CallTask4 = new Thread(Task4);
            CallTask4.Start();

            Thread CallTask5 = new Thread(Task5);
            CallTask5.Start();

            Thread CallTask6 = new Thread(Task6);
            CallTask6.Start();

            Thread CallTask7 = new Thread(Task7);
            CallTask7.Start();

            Thread CallTask8 = new Thread(Task8);
            CallTask8.Start();

            Thread CallTask9 = new Thread(Task9);
            CallTask9.Start();

            Thread CallTask10 = new Thread(Task10);
            CallTask10.Start();

        }

        public static void Task1()
        {
           ProcessDataTask1.CallAPI().Wait();       
        }

        public static void Task2()
        {        
            ProcessDataTask2.CallAPI().Wait();
        }

        public static void Task3()
        {
            ProcessDataTask3.CallAPI().Wait();
        }

        public static void Task4()
        {
            ProcessDataTask4.CallAPI().Wait();
        }
        public static void Task5()
        {
            ProcessDataTask5.CallAPI().Wait();
        }
        public static void Task6()
        {
            ProcessDataTask6.CallAPI().Wait();
        }

        public static void Task7()
        {
            ProcessDataTask7.CallAPI().Wait();
        }

        public static void Task8()
        {
            ProcessDataTask8.CallAPI().Wait();
        }

        public static void Task9()
        {
            ProcessDataTask9.CallAPI().Wait();
        }

        public static void Task10()
        {
            ProcessDataTask10.CallAPI().Wait();
        }
    }

All replies (4)

Wednesday, August 5, 2020 3:40 PM ✅Answered

but in this code, you create a thread for each task, then use Task.Run() to create (even though its pooled) another thread to run the code. You should do one or the other.

Task.Run() is just a thread manager. It uses real threads, i just has a pool. This allows to control the max threads, and reuse.

the problem with the original code, is the program was exiting before threads could complete. while thread wait is better, you could do Console.Read().

the proper way is after

            // start threads            
            Thread CallTask1 = new Thread(Task1);
            CallTask1.Start();

            Thread CallTask2 = new Thread(Task2);
            CallTask2.Start();

            Thread CallTask3 = new Thread(Task3);
            CallTask3.Start();

            Thread CallTask4 = new Thread(Task4);
            CallTask4.Start();

            Thread CallTask5 = new Thread(Task5);
            CallTask5.Start();

            Thread CallTask6 = new Thread(Task6);
            CallTask6.Start();

            Thread CallTask7 = new Thread(Task7);
            CallTask7.Start();

            Thread CallTask8 = new Thread(Task8);
            CallTask8.Start();

            Thread CallTask9 = new Thread(Task9);
            CallTask9.Start();

            Thread CallTask10 = new Thread(Task10);
            CallTask10.Start();

            // wait completion (could put threads in an array or use a sync counter)
            CallTask1.Join();
            CallTask2.Join();
            CallTask3.Join();
            CallTask4.Join();
            CallTask5.Join();
            CallTask6.Join();
            CallTask7.Join();
            CallTask8.Join();
            CallTask9.Join();
            CallTask10.Join();

Wednesday, August 5, 2020 10:42 PM ✅Answered

Tasks are wrappers around threads. besides including a pool, they simplify managing threads. the C# language has added direct support for Task. see async and await. with tasks the code could be:

        static void Main(string[] args)
        {
        var list = new List<Task>();
        
        list.Add(Task.Run(() => Task1()));
        list.Add(Task.Run(() => Task2()));
        list.Add(Task.Run(() => Task3()));
        list.Add(Task.Run(() => Task4()));
        list.Add(Task.Run(() => Task5()));
        list.Add(Task.Run(() => Task6()));
        list.Add(Task.Run(() => Task7()));
        list.Add(Task.Run(() => Task8()));
        list.Add(Task.Run(() => Task9()));
        list.Add(Task.Run(() => Task10()));
        
        Task.WaitAll(list.ToArray());
        }

or if you made the method Tasks

public static Task Task11() 
{
   return Task.Run(() => Console.WriteLine("task4"));
}

then its

    list.Add(Task11());

or you can use await

   await Task11();

the advantage of await over Task.Wait(), is that the thread is released for more work. all the code after the await, to the end of the method is placed in a ContinueWith() routine by the compiler.

if you know promises, Tasks are similar (though with different method names).

also when using Tasks, you can catch errors.

also Tasks work with async methods which run on the current thread, so a background thread is not required. all I/O is async and so are timers.

 

   


Wednesday, August 5, 2020 3:21 AM

Hi brucey,

 

The problem is that you misunderstand the Task and Thread concept.

  1. The Thread class is used for creating and manipulating a thread in Windows. A Task represents some asynchronous operation and is part of the Task Parallel Library, a set of APIs for running tasks asynchronously and in parallel.
  2. A new Thread()is not dealing with Thread pool thread, whereas Task does use thread pool thread.
  3. A task can have multiple processes happening at the same time. Threads can only have one task running at a time.
  4. A Task is a higher level concept than Thread.

To summarize, if you start a task inside a thread, what you actually do is to push a task using thread pool thread. In short, you use this thread to call another thread to do this task.

 

You could use below codes to prove above explanations.

static void Main(string[] args)
        {

            Thread CallTask1 = new Thread(Task1);
            

            Thread CallTask2 = new Thread(Task2);
            

            Thread CallTask3 = new Thread(Task3);
            

            Thread CallTask4 = new Thread(Task4);

            Thread CallTask5 = new Thread(Task5);

            Thread CallTask6 = new Thread(Task6);
            

            Thread CallTask7 = new Thread(Task7);
           

            Thread CallTask8 = new Thread(Task8);
            

            Thread CallTask9 = new Thread(Task9);
           

            Thread CallTask10 = new Thread(Task10);

            Console.WriteLine("Start:");


            CallTask1.Start();
            CallTask2.Start();
            CallTask3.Start();
            CallTask4.Start();
            CallTask5.Start();
            CallTask6.Start();
            CallTask7.Start();
            CallTask8.Start();
            CallTask9.Start();
            CallTask10.Start();

            

            Console.ReadLine();
        }
        public static void Task1()
        {
            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task2()
        {

            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static void Task3()
        {

            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task4()
        {

            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static void Task5()
        {

            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task6()
        {

            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task7()
        {
            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task8()
        {
            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static void Task9()
        {
            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);

        }

        public static void Task10()
        {
            Task.Run(() => {
                Console.WriteLine("Task={0}, Thread={1}",
                                  Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }).Wait();

            Console.WriteLine("Manually created Thread ID: " + Thread.CurrentThread.ManagedThreadId);
        }

Result:

 

Hope this could help you.

Best regards,

Sean


Wednesday, August 5, 2020 4:00 PM

Thanks again bruce,

I've been told to use Tasks as they are more efficient, I really need to read up on Threads & Tasks...

Are Threads and Tasks not really the same thing apart from Task will reuse a Threads...