Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Threads receiving wrong parameters

I need to run a method with a given parameter in a thread. I've noticed that when I run it, the parameter is wrong. For the example given, I have an array int[] output with the numbers 1-7. For each number, I create a thread with the method WriteInt(i). I expect the output to be 1-7 in any order, but I consistently see some numbers missed and others duplicated. What is going on and what would the correct way be to start these threads?

(The list is only there to join the threads afterwards)

class Program
{
    static void Main(string[] args)
    {
        int[] output = { 1, 2, 3, 4, 5, 6, 7 };

        List<Thread> runningThreads = new List<Thread>();

        foreach (int i in output)
        {
            Thread thread = new Thread(() => WriteInt(i));
            thread.Start();
            runningThreads.Add(thread);
        }
        foreach(Thread t in runningThreads)
        {
            t.Join();
        }
    }

    private static void WriteInt(int i)
    {
        Console.WriteLine(i);
    }
}

Example output:

3
3
4
5
6
7
like image 604
SaulBack Avatar asked Sep 07 '12 19:09

SaulBack


People also ask

How to pass multiple parameters in thread function?

Passing Multiple Arguments to Threads. When passing multiple arguments to a child thread, the standard approach is to group the arguments within a struct declaration, as shown in Code Listing 6.9. The address of the struct instance gets passed as the arg to pthread_create() .

Can we pass parameter in thread?

The first way we can send a parameter to a thread is simply providing it to our Runnable or Callable in their constructor. Note that the reason this works is that we've handed our class its state before launching the thread.

What are the parameters of threads?

Describes the effect of the threads parameter in parallel. You manage the number of threads that CPLEX uses with the global thread count parameter ( Threads , CPX_PARAM_THREADS ) documented in the CPLEX Parameters Reference Manual.

How do you pass a parameter to a thread in C++?

Example 1 - Thread Argument Passing long taskids[NUM_THREADS]; for(t=0; t<NUM_THREADS; t++) { taskids[t] = t; printf("Creating thread %ld\n", t); rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]); ... } See the source code.


1 Answers

The closure created by the lambda (() => WriteInt(i)) is getting closing over the variable i, not the value set to i within each iteration. As the thread runs, it uses the value set within i at that point in time, which is likely already been changed due to the foreach loop processing.

You need a temporary:

foreach (int i in output)
{
        int temp = i;
        Thread thread = new Thread(() => WriteInt(temp));
        thread.Start();
        runningThreads.Add(thread);
}

For details on what's happening, see Eric Lippert's post titled Closing over the loop variable considered harmful.

Also, in C# 5 (VS2012), this is no longer an issue for foreach loops. It will still happen with a for loop, however.

like image 116
Reed Copsey Avatar answered Oct 03 '22 13:10

Reed Copsey