0

I wrote a program that works with multithreading.
The program will launch 4 threads, create a queue of 400 links and each thread will get link from the queue and send a GET request to this link.

I created 4 threads using ThreadPool:

for (int i = 0; i < 4; i++)
{
    ThreadPool.QueueUserWorkItem(state => worker(i));
}

The worker() function should print the worker id I gave it as an argument:

Console.WriteLine("Worker {0} is processing item {1} with result {2}", workerId, workItem, res);  

I am expecting it to print something like that "Worker 1...., Worker 2 ..., Worker 3 ..., Worker 4 ..., Worker 1 ...".
But when I run the program it prints the same id 4 ("Worker 4"):
enter image description here

Full code:

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace PalyGround
{
    class Program
    {
        static void Main(string[] args)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();
            RunThreadPool();
            watch.Stop();
            var elapsedMs = watch.ElapsedMilliseconds;
            Console.WriteLine("[*] Elapsed time: {0}", elapsedMs / 1000);
            Console.ReadLine();
        }

        static BlockingCollection<string> inputQueue = new BlockingCollection<string>();

        // https://stackoverflow.com/questions/6529659/wait-for-queueuserworkitem-to-complete
        private static ManualResetEvent resetEvent = new ManualResetEvent(false);

        private static void RunThreadPool()
        {
            string url = @"https://google.com";
            for (int i = 0; i < 4; i++)
            {
                ThreadPool.QueueUserWorkItem(state => worker(i));
            }

            for (int i = 0; i < 400; ++i)
            {
                //Console.WriteLine("Queueing work item {0}", url + "/" + i);
                inputQueue.Add(url + "/" + i);
                //Thread.Sleep(50);
            }

            Console.WriteLine("Stopping adding.");
            inputQueue.CompleteAdding();

            resetEvent.WaitOne();
            Console.WriteLine("Done.");
        }

        // https://stackoverflow.com/a/22689821/2153777
        static void worker(int workerId)
        {
            Console.WriteLine("Worker {0} is starting.", workerId);

            foreach (var workItem in inputQueue.GetConsumingEnumerable())
            {
                string res = "";
                //Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem);
                try
                {
                    res = Get(workItem);
                }
                catch (Exception)
                {
                    res = "404";
                }
                Console.WriteLine("Worker {0} is processing item {1} with result {2}", workerId, workItem, res);
                //Thread.Sleep(100);          // Simulate work.
            }
            resetEvent.Set();
            Console.WriteLine("Worker {0} is stopping.", workerId);
        }

        // https://stackoverflow.com/a/27108442/2153777
        public static string Get(string uri)
        {
            HttpStatusCode status;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                status = response.StatusCode;
            }

            //Thread.Sleep(2000);
            return status.ToString() + "; Thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        }
    }
}
E235
  • 11,560
  • 24
  • 91
  • 141
  • 1
    The short answer is to change `ThreadPool.QueueUserWorkItem(state => worker(i));` to `var bob = i; ThreadPool.QueueUserWorkItem(state => worker(bob));` – mjwills Dec 01 '18 at 11:07
  • @mjwills yes, it seems to be similar question. thanks. – E235 Dec 01 '18 at 11:08
  • 1
    Just for the record: You don't *create* threads with QueueUserWorkItem. The thread pool decides if it needs to create new threads or not. You just schedule work on the thread pool. – Stefan Ossendorf Dec 01 '18 at 11:39

0 Answers0