使用参数创建新线程时索引超出范围? [英] Index out of bounds when create new thread with parameters?

查看:92
本文介绍了使用参数创建新线程时索引超出范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究有关烘焙算法的项目,但是我在C#中没有该算法的任何演示.由于这种情况,我已经转换了一些我在Wikipedia上找到的Java代码.但是无论如何,它似乎不起作用!

I'm working on my project about Bakery Algorithm but i don't have any demo of that Algorithm in C# . Because of that situation i've converted some java code that i found on Wikipedia . But Anyway , it doesn't seem to work !

已更新:这是我的完整代码(旧代码包含在"//"注释中)

Updated : Here's my full-working code ( old code include in "//" comment )

namespace BakeryAlgorithm
{
    class Program
    {
        static int threads = 10;
        static string x = "";
        static int count = 0;
        static int[] ticket = new int[threads];
        static bool[] entering = new bool[threads];

        public static void doLock(int pid)
        {

                entering[pid] = true;

            int max = 0;

            for (int i = 0; i < threads; i++)
            {
                if (ticket[i] > ticket[max]) { max = i; }
            } 

            ticket[pid] = 1+max;
            entering[pid] = false;

            for (int i = 0; i < threads; ++i)
            {
                if (i != pid)
                {
                    while (entering[i]) 
                    {
                        Thread.Yield();   
                    } 
                    while (ticket[i] != 0 && (ticket[pid] > ticket[i] ||
                              (ticket[pid] == ticket[i] && pid > i)))
                    {
                        Thread.Yield();
                    }
                }
            }
if (x == "C" || x == "c")
                    Console.WriteLine("[System] PID " + pid.ToString() + " get into critical section");   

        }

        public static void unlock(int pid)
        {
            ticket[pid] = 0;
            count++;
            Console.WriteLine("[Thread] PID " + pid.ToString() + " process completed");
        }

        public static void arrayInit()
        {
            for (int i = 0; i < threads; i++)
            {
                ticket[i] = 0;
                entering[i] = false;
            }
        }

        public static void simThread(int i)
        {
            doLock(i);
            if (x == "C" || x=="c")
            Console.WriteLine("[Thread] PID " + i.ToString() + " begin to process...");

            Random rand = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
            int a = rand.Next(5,10); 
            int b = rand.Next(1,5);
            int c = rand.Next(1,4);

            double d = 0;
            string o="";

            if (c == 1)
            {
                d = a + b;
                o=" + ";
            }
            else if (c == 2)
            {
                d = a * b;
                o=" * ";
            }
            else if (c == 3)
            {
                d = a / b;
                o=" / ";
            }
            else
            {
                d = a - b;
                o=" - ";
            }

            if (x == "C" || x == "c")
                Console.WriteLine("Result of PID " +i.ToString() +" : " + a.ToString() + o + b.ToString() + "=" + d.ToString());
            unlock(i);
        }
        [STAThread]
        static void Main(string[] args)
        {
            arrayInit();
            string choice="C";
            while (choice == "C" || x == "c")
            {
                        Console.WriteLine("Do you want to see progress log ? (C=Yes,K=No) : ");
                        x = Console.ReadLine();
                        if (x == "")
                            x = "C";

                Console.Clear();
                Console.WriteLine("----------------------------------");
                Console.WriteLine("Bakery Algorithm in C#");
                Console.WriteLine("Number of threads : " + threads.ToString());
                Console.WriteLine("Progress Log");
                Console.WriteLine("----------------------------------");

                Thread[] threadArray = new Thread[threads];
                for (int i = 0; i < 10; i++)
                {
                    //New code that solved my problem
                    int copy = i;
                    threadArray[i] = new Thread(() => simThread(copy));
                    //My old code that cause my problem
                    //threadArray[i] = new Thread(() => simThread(i));
                    if (x == "C" || x == "c")
                    Console.WriteLine("[System] PID " + i.ToString() + " has been created");
                    threadArray[i].Start();
                    Thread.Sleep(20);
                }

                Console.ReadLine();
                Console.WriteLine("----------------------------------");
                Console.WriteLine("Process completed " + count.ToString() + "  threads !");
                count = 0;
                Console.WriteLine("----------------------------------");


                Console.WriteLine("Do you want to restart the algorithm (C=Yes,K=No)");
                        choice = Console.ReadLine();
                        if (choice == "")
                            choice = "C";
            }
        }
    }
}

推荐答案

这是问题所在

threadArray[i] = new Thread(() => simThread(i));

您要在此处捕获i-单个变量,该变量将在循环过程中进行更新,并最终以threads的值结束.

You're capturing i here - the single variable which will be updated over the course of the loop, and end up with a value of threads.

如果线程仅在循环完成后才实际执行lambda表达式的主体 ,则该值基本上是不合适的……即使不这样做,您也很容易拥有多个线程使用相同的i值.

If the thread only actually executes the body of the lambda expression after the loop is completed, that value will basically be inappropriate... and even if it doesn't, you could easily have multiple threads using the same value of i.

对于循环的每次迭代,您基本上都需要一个单独的变量,例如

You basically want a separate variable for each iteration of the loop, e.g.

for (int i = 0; i < threads; i++)
{
    int copy = i;
    threadArray[i] = new Thread(() => simThread(copy));
    Console.WriteLine("[He Thong] PID " + i.ToString() + " duoc khoi tao");
    threadArray[i].Start();
}

这样,循环的每次迭代都会捕获一个单独的变量,该变量的迭代值为i,但随后不会更改.

That way each iteration of the loop captures a separate variable which has the value of i for that iteration, but which isn't then changed.

这是您当前代码和工作代码之间的最小变化-但就我个人而言,我希望进行更大的更改以更广泛地使用TPL,使用单独的独立对象而不是

That's the smallest change between your current code and working code - but personally I'd be looking to make larger changes to use the TPL more heavily, have separate self-contained objects instead of parallel arrays etc.

这篇关于使用参数创建新线程时索引超出范围?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆