从列表中添加和删除列表时出现“索引超出范围”错误

时间:2018-11-07 14:00:01

标签: c# multithreading list

我想添加/删除列表,但出现“索引超出范围”异常。在我的代码中,我每秒添加2次数据直到10。然后通过使用线程将其删除。我也使用信号量进行阻止。我想同时使用3个线程。

这是我的代码

 class Program
{
    private static Thread[] threads = new Thread[3];
    private static Semaphore sem = new Semaphore(3, 3);
    private static List<string> messagesList = new List<string>();
    private static readonly object _kilit = new object();
    static void Main(string[] args)
    {
        Thread addData = new Thread(AddData);
        addData.Start();

        for (int j = 0; j < 3; j++)
        {
            threads[j] = new Thread(AddComma);
            threads[j].Name = "thread_" + j;
            threads[j].Start();
        }
    }
    public static void AddData()
    {

        for (int i = 0; i < 10; i++)
        {

            messagesList.Add("data");
            messagesList.Add("data");                
            Thread.Sleep(1000);

        }

    }
    public static void AddComma()
    {
        sem.WaitOne();
        while (true) {                
            if (messagesList.Count > 0)
            {

                    Console.WriteLine();
                    Console.WriteLine(Thread.CurrentThread.Name + "Entering to Critical section");
                    int averageIndex = messagesList[0].ToString().Length / 2; // Here is the error
                    string msg = messagesList[0].ToString().Substring(0, averageIndex) + "," + messagesList[0].ToString().Substring(averageIndex);
                    Console.WriteLine(msg);
                    messagesList.RemoveAt(0);
                    Console.WriteLine(Thread.CurrentThread.Name + "Exiting from Critical Section");                                   

            }             
        }
        sem.Release();

    }
}

2 个答案:

答案 0 :(得分:3)

您允许三个线程同时运行:

new Semaphore(3, 3);

因此您的Semaphore并没有真正帮助您,因为您并未真正阻止。因此,您仍然遇到问题,例如,列表中可能剩下一条消息,但是3个线程都将messagesList.Count > 0评估为true。这些线程之一将首先从列表中删除该项目,这将导致其他两个抛出异常。

有更好的方法可以做到这一点。对于列表,我喜欢使用具有读锁和写锁的ReaderWriterLockSlim。它允许所有线程读取,但在您获得写锁后将阻止所有人。在文档中有一个如何使用它的示例。

答案 1 :(得分:2)

问题1:您允许3个并发线程访问列表,应为new Semaphore(1,1);

问题2:永远不会调用sem.Release()(由于while(true)而导致无法访问的代码),因此您必须将sem.WaitOne()移到第一个语句中,而将block和sem.Release()移到第一个语句中while块内的最后一行

工作代码:

class Program
{
    private static Thread[] threads = new Thread[3];
    private static Semaphore sem = new Semaphore(1, 1);
    private static List<string> messagesList = new List<string>();
    private static readonly object _kilit = new object();
    static void Main(string[] args)
    {
        Thread addData = new Thread(AddData);
        addData.Start();

        for (int j = 0; j < 3; j++)
        {
            threads[j] = new Thread(AddComma);
            threads[j].Name = "thread_" + j;
            threads[j].Start();
        }
    }
    public static void AddData()
    {

        for (int i = 0; i < 10; i++)
        {

            messagesList.Add("data");
            messagesList.Add("data");
            Thread.Sleep(1000);

        }

    }
    public static void AddComma()
    {

        while (true)
        {
            sem.WaitOne();
            if (messagesList.Count > 0)
            {

                Console.WriteLine();
                Console.WriteLine(Thread.CurrentThread.Name + "Entering to Critical section");
                int averageIndex = messagesList[0].ToString().Length / 2; // Here is the error
                string msg = messagesList[0].ToString().Substring(0, averageIndex) + "," + messagesList[0].ToString().Substring(averageIndex);
                Console.WriteLine(msg);
                messagesList.RemoveAt(0);
                Console.WriteLine(Thread.CurrentThread.Name + "Exiting from Critical Section");

            }
            sem.Release();
        }
    }
}