1

I'm working on my university project. One of main requirement is to use multithreading (user can choose threads numbers).

I'm new in C# and based on internet research. I choose ThreadPool.

I spent a lot of time observing how the threads act using parallel watch in VS and i have no idea how this thing works. For example threadNumber = 10 but parallel watch shows only 4 activated threads.

Here is my code:

public void calculateBeta()
    {
        var finished = new CountdownEvent(1);
        for (int i = 0; i < threadNumber; i++)
        {
            finished.AddCount();
            ThreadPool.QueueUserWorkItem(
            (state) =>
            {
                try
                {
                   doSth();
                }
                finally
                {
                    finished.Signal();
                }
            });
        }
        finished.Signal();
        finished.Wait();
    }

What am I doing wrong? I tried to test this code with many different values of threads number and it didn't work as i looked for.

EDIT:

 private void myTask(object index)
    {

            int z = (int)index;
            double[] result = countBeta(createTableB(z), createTableDiagonalA(z));
            int counter = 0;
            if ((rest != 0) && (z == threadNumber - 1))
            {
                for (int j = z * numbersInRow; j < (z + 1) * numbersInRow + rest; j++)
                {
                    N[j] = result[counter];
                    counter++;
                }
            }
            else
            {
                for (int j = z * numbersInRow; j < (z + 1) * numbersInRow; j++)
                {
                    N[j] = result[counter];
                    counter++;
                }
            }
            threads[z] = true;
    }


public void calculateBeta()
    {
        N = new double[num];
        setThreadNumber(2);
        checkThreadNumber();
        setNumberInRow();
        setRest();
        threads = new bool[threadNumber];
        for (int i = 0; i < threadNumber; i++)
        {
            Thread thread = new Thread(this.myTask);
            thread.IsBackground = true;
            thread.Start(i);
        }
        while (!checkThreads())
        {
        }
    }

private bool checkThread()
    {
        bool result = true;
        for (int i = 0; i < threads.Length; i++)
        {
            if (!threads[i])
                result = false;
        }

        return result;
    }

static void Main(string[] args)
    {


        Jacobi jacobi = new Jacobi();
        Console.WriteLine("Metoda Jacobiego");
        Console.WriteLine("Rozwiazywanie ukladu n-rownan z n-niewiadomymi Ax=b");
        jacobi.getNum();
        jacobi.getA();
        jacobi.getB();
        jacobi.calculateBeta();
        jacobi.calculateM();
        jacobi.calculateX();
        jacobi.countNorms();
        Console.ReadLine();
    }

I need results from calculateBeta to further calculations. Sometimes threads are not finished yet but the program moves forward without data that need to be provided by threads. I'm using bool variable now but this solution is not an elegant way to deal with it(Creating bool table, checking if all thread are fnished) How can i manage with that in a different way?

sheddar
  • 270
  • 1
  • 4
  • 16
  • 1
    The thread pool won't make too many threads. – SLaks Jan 13 '15 at 15:29
  • How long does the `doSth` takes to complete? I explained about threadpool a little [here](http://stackoverflow.com/a/26141323/2530848). That might help. – Sriram Sakthivel Jan 13 '15 at 15:37
  • 3
    This is very well covered already. Just google "how does the .net threadpool work?" and start reading from the top. – Hans Passant Jan 13 '15 at 15:42
  • @kobasek: I added another snippet to my answer demonstrating the use of the `Thread.Join` method to synchronize the execution of threads to a point in the code (per your discussion w/ LPs below and edits to your OP). Take a look. Overview: You don't need to keep checking to see if a thread is done with an array of bools. Just launch your threads and "wait" until they are complete. (Btw, the Windows/.NET threading APIs and terminology, IMO, can be very counter-intuitive and confusing!) – Paul Sasik Jan 14 '15 at 17:04
  • Threads work well when you need to free up the user interface from long-running background tasks or when you can divide and conquer some set of data and processing between threads. If you're just running some calculations with a small set of data, threading will not help. Good uses of threads: image processing, sorting, searching. – Paul Sasik Jan 14 '15 at 20:02

3 Answers3

1
// Array of threads launched. 
// This array is useful to trace threads status.
Thread[] threads;

private void myTask(object index)
{
    Console.Write("myTask {0} started\n", index);
    Console.Write("myTask {0} finisced\n", index);
}

public void calculateBeta(UInt16 threadNumber)
{
    // Allocate a new array with size of requested number of threads
    threads = new Thread[threadNumber];

    // For each thread
    for (int i = 0; i < threadNumber; i++)
    {
        // Thread creation
        threads[i] = new Thread(this.myTask);

        // IsBackground set to true grants that the allication can be "killed" without wait for all threads termination
        // This is useful in debug to be sure that an error in task doesn't freeze the app.
        // Leave it to false in release
        #if DEBUG
        threads[i].IsBackground = true;
        #endif

        // Start the thread
        threads[i].Start(i);
    }

    // Waits until all threads complete.
    while (!checkThreads());
}

private bool checkThreads()
{
    bool result = true;
    for (int i = 0; i < threads.Length; i++)
    {
        // If the thread wasn't disposed
        if (threads[i] != null)
        {
            // Check if the thead is alive (means is working)
            if (threads[i].IsAlive == true) 
            {
                result = false;
            }
            else // The thread is not working 
            {
                // Dispose the thread
                threads[i].Join();
                // Set pointer to null to signal that the task was 
                threads[i] = null;
            }
        }
    }

    return result;
}


private void Button_Click(object sender, RoutedEventArgs e)
{
    Console.Write("Starting tasks!!\n");

    calculateBeta(10);

    Console.Write("All tasks finished!!\n");
}
LPs
  • 16,045
  • 8
  • 30
  • 61
  • How can pass variable to yourTask method? – sheddar Jan 13 '15 at 17:48
  • With some modifications this code will run but there is a ton of code that is unnecessary to demonstrate the concept. This extra code just becomes cruft and five lines of code is all you really need. Both the `while` loop and `Thread.Sleep` call in the `yourTask` method can be removed. Why not just a simple `Console.Write` call or even just the comment `// DO YOUR STUFF` alone? In the `Button_Click` method the `threads` array is completely unnecessary. Setting `IsBackground` to `true` is unnecessary for this example. You really just need two lines of code to spawn an N number of threads. – Paul Sasik Jan 14 '15 at 04:47
  • @Paul Firstly the array was mandatory in my solution if the task has a while. How could you terminate/stop it without a reference for each single task? Secondly where, in the question, is write that tasks has to be simple and have to ends itselfs at the end of their code? Thirdly: for an example to a newbie, I think, is better to set IsBackground to true to avoid test application to freeze. MSDN wrote: **Background threads are identical to foreground threads, except that background threads do not prevent a process from terminating**. – LPs Jan 14 '15 at 07:14
  • @ Kobasek See this post: [link](http://stackoverflow.com/questions/3360555/how-to-pass-parameters-to-threadstart-method-in-thread) – LPs Jan 14 '15 at 07:18
  • Thanks guys for help. I used this code from @Paul and it works. But now i have a problem with thread managament(Threads are running, calculating data but sometimes program moves forward. Threads are not finished and other methods are executed without data needed) . I'm trying to deal with it using bool variable. Creating bool table, checking if all thread are finished is not an elegant solution. Can i manage with that in a different way? – sheddar Jan 14 '15 at 08:24
  • I think is better if you can post your code to understand better your problem. – LPs Jan 14 '15 at 08:31
  • `if (!threads[i])` is an error. How can ou compile it? That check has to be `if (threads[i].IsAlive == true)` – LPs Jan 14 '15 at 11:12
  • threads is a bool table. When one of threads is finished it sets in threads table true value. When all of cells in table are set with true value then the program can move forward. – sheddar Jan 14 '15 at 12:28
  • @LPs: How could an array of threads possibly be of any use to you if you declare it at function scope? The code you posted is far from being able to run properly and, IMO, detracts from the benefits that may be there for the OP. Also, you posted a bunch of code without much context or comments. – Paul Sasik Jan 14 '15 at 15:32
  • Btw @LPs, I don't mean to just bash on your answer. I was actually pretty close to up-voting and moving on until I took a closer look and arrived at my conclusions and updates to my own answer. IMHO your answer could be much improved. If you put in some work on it up, e.g. adding comments, taking out the infinite loop etc. and let me know I promise to come back and up-vote. Thanks. – Paul Sasik Jan 14 '15 at 17:08
  • @Paul I posted the final solution for me. Btw I think that this "forum" is aiming to give a trace for user that are asking for an help. In the contrary, if someone wants to have a complete solution, he can just hire a consultant.. ;) – LPs Jan 15 '15 at 13:11
1

This is because you're using ThreadPool to manage your threads. It will create a certain number of threads based on many factors. You can tweak some of the settings but by and large when you commit to using ThreadPool to managing your threads you commit to a black box. Check out GetMaxThreads and GetMinThreads and their setter counterparts for some of your options.

Check out this ThreadPool Architecture article on MSDN. It gives good background to the hows and whys of the class. But in the introductory paragraph you will see this sentence, which is key to your conundrum:

The thread pool is primarily used to reduce the number of application threads and provide management of the worker threads.

If you want to have the kind of control where you launch 10 threads in quick succession you should avoid ThreadPool and just manage the threads yourself. Here is a simple, absolutely minimal example of launching ten threads and also passing different data to each, in this case an index:

void ButtonClickHandlerOrSomeOtherMethod()  
{
    for (int i=1; i<=10; i++) // using a 1-based index
    {
        new Thread(ThreadTask).Start(i);
    }
}

void ThreadTask(object i) 
{
    Console.WriteLine("Thread " + i + " ID: " + Thread.CurrentThread.ManagedThreadId);
}

And some sample output:

Thread 1 ID: 19
Thread 2 ID: 34
Thread 3 ID: 26
Thread 4 ID: 5
Thread 5 ID: 36
Thread 6 ID: 18
Thread 7 ID: 9
Thread 8 ID: 38
Thread 9 ID: 39
Thread 10 ID: 40

Follow-up code demonstrating synching with threads and "waiting" until they are all finished:

void ButtonClickHandlerOrSomeOtherMethod() 
{
    // need a collection of threads to call Join after Start(s)
    var threads = new List<Thread>();

    // create threads, add to List and start them
    for (int i=1; i<=10; i++) {
        var thread = new Thread(ThreadTask);
        threads.Add(thread);
        // a background thread will allow main app to exit even
        // if the thread is still running
        thread.IsBackground = true;
        thread.Start(i);
    }

    // call Join on each thread which makes this thread wait on
    // all 10 other threads
    foreach (var thread in threads) 
        thread.Join();

    // this message will not show until all threads are finished
    Console.WriteLine("All threads finished.");
}

void ThreadTask(object i) 
{
    Console.WriteLine("Thread " + i + " ID: " + Thread.CurrentThread.ManagedThreadId);
    // introducing some randomness to how long a task "works on something"
    Thread.Sleep(100 * new Random().Next(0, 10));
    Console.WriteLine("Thread " + i + " finished.");
}
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
  • Thank you very much for help, it works fine. I was testing threads for a while and i have one question. Results are very confusing, i have no idea what happend. First of all, my program without multithreading does the calculations quicker then multithreading version(tested with a big amount of input data) Furthermore the time of calculation is different every time for the same data(38 ms, 60 ms, 96 ms) 1 ms for version without threads. Number of used threads was 4,5,6. I guess it's not normal, that doesn't make any sense and logic. What do you think about it? – sheddar Jan 14 '15 at 18:08
  • @kobasek - Yes, all those can be answered. It is a common misconception that multi-threaded means faster. This is rarely true actually. There is overhead to creating threads and unless the algorithm uses threads very well it will not be faster. The differences in calculation times can be explained by differences in your computer's activity over time. Programs share a computer's resources and sometimes, depending on the timing, a thread may have to wait for processor time. When you do performance testing you should run many tests and take an average. – Paul Sasik Jan 14 '15 at 19:57
1

The whole design of the thread pool is that it doesn't have to create a new actual thread every time a new item is queued up. If the pool notices that it has items pending in the queue for an extended period of time it will eventually start spinning up new threads, over time. If you're continually saturating the thread pool with operations, you'll see the number of actual threads rise. It will also only add new threads up to a limit; based on what it feels is going to have the best throughput. For example, it will avoid creating a lot more threads than cores assuming all of the threads are actively running CPU bound work.

The idea of using the thread pool is if you don't care how many actual threads there are, but rather just want to have efficient throughput of the operations that you have, allowing the framework lots of freedom on how to best optimize that work. If you have very specific requirements as to how many threads you have, you'll need to create threads manually rather than using a pool.

Servy
  • 202,030
  • 26
  • 332
  • 449