Weird Threading with C #

I am having a strange problem with C # streams.

This is my sample program that uses a thread to activate the Print () function for each agent in agentList.

class Program {

    static void Main(string[] args) {

        List<Agent> agentList = new List<Agent>();

        agentList.Add(new Agent("lion"));
        agentList.Add(new Agent("cat"));
        agentList.Add(new Agent("dog"));
        agentList.Add(new Agent("bird"));

        foreach (var agent in agentList) {
            new Thread(() => agent.Print()).Start();
        }

        Console.ReadLine();
    }
}

class Agent {
    public string Name { get; set; }

    public Agent(string name) {
        this.Name = name;
    }

    public void Print() {
        Console.WriteLine("Agent {0} is called", this.Name);
    }
}

And here is the result when I run the above program:

Agent cat is called
Agent dog is called
Agent bird is called
Agent bird is called

But I was expecting something to contain all 4 agents of type

Agent lion is called
Agent cat is called
Agent dog is called
Agent bird is called

The most amazing thing is that if I call threads outside of foreach, it works!

class Program {
    static void Main(string[] args) {
        List<Agent> agentList = new List<Agent>();

        agentList.Add(new Agent("leecom"));
        agentList.Add(new Agent("huanlv"));
        agentList.Add(new Agent("peter"));
        agentList.Add(new Agent("steve"));

        new Thread(() => agentList[0].Print()).Start();
        new Thread(() => agentList[1].Print()).Start();
        new Thread(() => agentList[2].Print()).Start();
        new Thread(() => agentList[3].Print()).Start();


        Console.ReadLine();
    }
}

The result of the above code is exactly what I expected. So what's the problem here?

+5
source share
5 answers

You have a closure. You close the variable inside the foreach loop. The fact is that the variable is overwritten before the start of the stream, so you have two iterations with the same value.

, foreach :

foreach(var a in agentList)
{
    var agent = a;
    new Thread(() => agent.Print()).Start();
}
+9

agent , . :

    foreach (var agent in agentList) {
        var temp = agent;
        new Thread(() => temp.Print()).Start();
    }
+2

foreach :

foreach (var agent in agentList) 
{
    var agent1 = agent;
    new Thread(() => agent1.Print()).Start();         
} 

( ) , .

+1

- var, refrence . , .

0

- (, ManualResetEvent) . , , .

BackgroundWorker:

List<Agent> agentList = new List<Agent>();

agentList.Add(new Agent("leecom"));
agentList.Add(new Agent("huanlv"));
agentList.Add(new Agent("peter"));
agentList.Add(new Agent("steve"));

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
    foreach (var item in agentList)
    {
        item.Print();
    }
};

worker.RunWorkerAsync();
-1

All Articles