并行任务处理共享变量

时间:2014-11-07 12:55:00

标签: c# task-parallel-library

我从任务库开始。我写了像

这样的简单代码
private void button1_Click(object sender, EventArgs e)
{
    simpleMost();
}

string mesg;
void simpleMost()
{
    mesg = "";
    button1.Enabled = false;

    Task t1 = new Task(delegate { makeResult(1); });
    Task t2 = new Task(delegate { makeResult(2); });
    Task t3 = new Task(delegate { makeResult(3); });

    t1.Start();
    t2.Start();
    t3.Start();

    t1.Wait();
    t2.Wait();
    t3.Wait();

    richTextBox1.Text = mesg;
    button1.Enabled = true;
}

void makeResult(int a)
{
    mesg += "\nTask" + a;
}

我再次点击我的button1并获得以下输出

1

Task3
Task1
Task2

2

Task1
Task2
Task3

3

Task1
Task2
Task3

4

Task2
Task3

5

Task1
Task3

6

Task1
Task2

在4,5,6个案例中,为什么makeResult无法正常工作。当我在等待语句后检查任务状态时,发现它们都已完成,但是其中一个错过了传递给它的函数的正确执行

2 个答案:

答案 0 :(得分:2)

您有几个任务,每个任务都以非原子方式修改相同的共享资源。

mesg += "\nTask" + a;

实际上是:

mesg = mesg + "\nTask" + a;

...所以如果一个任务读取 mesg,那么另一个任务会向其写一个新值,然后第一个任务将使用旧值连接字符串,并写下回到变量。

避免这种情况的最简单方法是使用锁定,这样一次只有一个线程可以执行修改语句。它不像它可能那么优雅,但它应该消除你目前的竞争条件。

答案 1 :(得分:1)

我认为有时两个任务试图同时访问“mesg”。尝试锁定。

object syncObject = new object();
void makeResult(int a)
{
    lock (syncObject)
    {
        mesg += "\nTask" + a;
    }
}