多线程未正确执行

时间:2013-05-13 13:19:26

标签: c# multithreading

我在这里有一个函数可以在多个线程中调用另一个函数。在第二个函数中,refValuesd [,]的每个元素的值是1.但是当我在调用多个线程之后检查graph1()函数中相同2D数组的元素时,我获得了元素的不同值。 refValuesd [,]。我是多线程的新手。

void graph1()
    {
        for (int j = 0; j < 366; j++) //loop to refresh element values
        {
            refValues[j] = 0;
            threshValues[j] = 0;
            y_Values[j] = 0;
            y__Values[j] = 0;
            yValues[j] = 0;
            for (int k = 0; k < 1000; k++)
            {
                threshValuesd[k,j] = 0;
                refValuesd[k,j] = 0;
                y__Valuesd[ k,j] = 0;
                y_Valuesd[k,j] = 0;
                yValuesd[k,j] = 0;
            }

        }

        List<string>[] list = new List<string>[4];//manpower details
        list = A.mandetselect();
        int number = A.Countmandet();//retuns an integer value
        string[] trade = list[1].ToArray();
        string[] license = list[2].ToArray();
        string[] training = list[3].ToArray();
        string[] display_status = list[4].ToArray();

        List<string>[] listc = new List<string>[14];//Project details
        listc = A.Select();
        int numberc = A.Count();

        string abc = "";
        int q = 0;
        for (int j = 0; j < number; j++)
        {

            if (!display_status[j].Equals("NO") && (selection == "ALL" || (selection == "ALL-LAE" && license[j] != "") || (selection == "ALL-NON LAE" && license[j] == "") || (selection == "AVIONICS -ALL" && trade[j] == "Avionics") || (selection == "AVIONICS-NON LAE" && trade[j] == "Avionics" && license[j] == "") || (selection == "AVIONICS-LAE" && trade[j] == "Avionics" && license[j] != "") || (selection == "AIRFRAME-ALL" && trade[j] == "Airframes") || (selection == "AIRFRAME-NON LAE" && trade[j] == "Airframes" && license[j] == "") || (selection == "AIRFRAME-LAE" && trade[j] == "Airframes" && license[j] != "")))
            {
                int z = numberc;
                string[] nameofproj = listc[0].ToArray();
                int copy = q;
                int copy2 = j;
                string a = abc;
                string[] name = list[0].ToArray();
                List<string>[] lista = new List<string>[5];
                string[] status = listc[13].ToArray();
                thread[copy] = new Thread(() => graph1threader(a, name[copy2], lista, z, nameofproj, status, copy));
                thread[copy].Start();

                q++;

            }
        }


        for (int j = 0; j < 366; j++)
        {
            for (int k = 0; k < q; k++)
            {
                threshValues[j] += threshValuesd[k, j];                   
                refValues[j] += refValuesd[k, j];
                y__Values[j] += y__Valuesd[k, j];
                y_Values[j] += y_Valuesd[k, j];
                yValues[j] += yValuesd[k, j];
            }
        }


            for (int j = 0; j < 366; j++)
            {
                DateTime temp = G.AddDays(j);
                string temper = temp.ToShortDateString();
                y__Values[j] = y__Values[j] - y_Values[j];
                xNames[j] = temper;
            }

        chart1.Series[1].Points.DataBindXY(xNames, y_Values);           


        chart1.Series[2].Points.DataBindXY(xNames, y__Values);


        chart1.Series[3].Points.DataBindXY(xNames, refValues);


        chart1.Series[4].Points.DataBindXY(xNames, threshValues);


        chart1.Series[5].Points.DataBindXY(xNames, yValues);



    }

这是在多个线程上执行的函数:

void graph1threader(string abc,string nameofj,List<string>[] lista,int numberc,string[] nameofproj,string[] status,int copy )
    {
        DBConnect A = new DBConnect();
        int x = copy;
        string[] projname;
        string[] country;
        string[] start;
        string[] end;
        abc = nameofj.Replace(" ", "_");
        lista = A.manprojselect(abc);
        projname = lista[0].ToArray();
        country = lista[2].ToArray();
        start = lista[3].ToArray();
        end = lista[4].ToArray();

        for (int k = 0; k < 366; k++)//basic
        {

            refValuesd[x, k]++;
             refValuesd[copy,k].ToString());
            threshValuesd[x, k] = 0.8;
            string Status = "";
            int flag = 0;

            for (int l = 0; l < A.Countproj(abc); l++)
            {

                for (int m = 0; m < numberc; m++)
                {
                    if (nameofproj[m] == projname[l])
                    {
                        Status = status[m];
                    }
                }


                DateTime shuru = DateTime.ParseExact(start[l],
                               "dd-MM-yyyy hh:mm:ss",
                               CultureInfo.InvariantCulture);
                DateTime anth = DateTime.ParseExact(end[l],
                               "dd-MM-yyyy hh:mm:ss",
                               CultureInfo.InvariantCulture);
                if (temp >= shuru && temp <= anth)
                {
                    if (Status != "PLANNED" && Status != "LO" && flag == 0)
                    {
                        y_Valuesd[x,k]++;//BASIC UTILISATION
                        flag = 1;
                    }
                    if (Status == "IP" || Status == "OTD")
                        y__Valuesd[x,k]++;//EXCESS
                    if (Status == "PLANNED")
                    {
                        yValuesd[x,k]++;//UNUTILISED

                    }

                }

            }


        }

    }

2 个答案:

答案 0 :(得分:2)

确保使用lock部分重新评估对重新评估的访问权限,然后您将从正确的方向开始。你必须设计你的锁定不要创建竞争条件和死锁。

编辑:因此,在审核了您的代码之后,这里有一些评论

看起来您启动了图形功能,而图形功能又在多个线程上执行graph1threader功能。我不会质疑这是否是必要的 - 假设你已经确定它是。

活动顺序

在继续第二个循环之前,您似乎不会停止等待所有graph1threader个线程完成。所以这是一个问题:

  • 您希望在继续之前完成graph1threader作业吗?

如果是这样,你看过Task吗?您可以将ThreadTask完全交换,而不是创建线程,然后,一旦完成所有Task对象的创建并启动它们,就可以将Task.WaitAll放在for (int j = 0; j < number; j++)之后{1}}循环等待它们完成,然后再执行for中的第三个graph1循环:

        thread[copy] = new Task(() => graph1threader(a, name[copy2], lista, z, nameofproj, status, copy));
        thread[copy].Start();
        q++;
    }
}
Task.WaitAll(thread);

for (int j = 0; j < 366; j++)
{
    for (int k = 0; k < q; k++)
    {
        threshValues[j] += threshValuesd[k, j];
        refValues[j] += refValuesd[k, j];
        y__Values[j] += y__Valuesd[k, j];
        y_Values[j] += y_Valuesd[k, j];
        yValues[j] += yValuesd[k, j];
    }
}

如果您不想使用Task(或不能)Thread.Join也可以使用,但Task支持取消比Thread更容易,所以如果你有一个具有长时间运行操作的UI,它将使您更轻松。

共享字段

两个函数都使用以下变量(请忽略任何不正确的变量类型,这是重要的名称):

double[,] threshValuesd;
int[,] refValuesd;
int[,] y__Valuesd;
int[,] y_Valuesd;
int[,] yValuesd;

我将此列表称为书签A 以便稍后使用

所有这些都可能需要防范多线程race conditions等。

如何保护共享字段

无论您是否等待,都需要保护graph1threader中的共享字段。所以,如果我已正确阅读您的代码:

  • 您将唯一的递增值传递给graph1threader(在图1中的第二个q++循环中使用for
  • 因此,以下几行不会竞争graph1threader中线程之间的设置值:
    • refValuesd[x, k]++;
    • threshValuesd[x, k] = 0.8;
    • y_Valuesd[x,k]++;
    • y__Valuesd[x,k]++;
    • yValuesd[x,k]++;

旁注:这些变量名称对我来说是不可理解的,您可以尝试使用比 yValuesdy_Valuesd y__Valuesd 以帮助您稍后调试)。

但是,即使线程不竞争更新同一个数组插槽中的值,您也可能会遇到内存障碍和对单个阵列插槽的读/写访问的问题。因此,我建议这样做,简单地声明一个类字段:

private readonly object SyncRoot = new object();

然后围绕所有访问我上面提到的任何共享字段书签A 你需要使用(选择你的第一个循环作为例子):

lock (this.SyncRoot) {
    for (int j = 0; j < 366; j++)
    {
        for (int k = 0; k < q; k++)
        {
            threshValues[j] += threshValuesd[k, j];
            refValues[j] += refValuesd[k, j];
            y__Values[j] += y__Valuesd[k, j];
            y_Values[j] += y_Valuesd[k, j];
            yValues[j] += yValuesd[k, j];
        }
    }
}

保持锁定调用尽可能不频繁,但尽可能靠近共享资源。我的意思是,如果你愿意,你可以锁定内部for循环,但这会慢一些,但是如果它们也锁定同一个对象,你可能需要允许其他线程更频繁地继续。 / p>

注意:这种使用共享锁的技术假设您希望graph1threader个线程与for中的第三个graph1循环同时运行(即我不需要关于Task个对象的评论)。如果不是这种情况,我认为你可以在每个函数中创建一个本地对象并锁定它。因此,每个线程都有一个不同的锁对象。因为没有线程同时访问数组中的同一个插槽,所以这只会强制执行内存屏障,并确保所有线程在读取时都看到相同的值。

对不起,这太长了,很难知道从哪里开始,而不知道你为构建这段代码所做的假设。

答案 1 :(得分:2)

那里可能存在一些问题,但我可以发现两个问题:

首先,线程正在尝试refValuesd[x, k]++,这不是线程安全的。

请改为尝试:

Interlocked.Increment(ref refValuesd[x, k]);

其次,在使用它们生成的数据之前,您不会等待所有线程终止。尝试在for (int j = 0; j < 366; j++)行之前添加此内容:

foreach (var thread in threads)
    thread.Join();

看起来你需要学习很多东西,所以我建议你阅读这本免费的电子书:

http://www.albahari.com/threading/