Ошибка «Индекс вне диапазона» при добавлении и удалении из списка - PullRequest
0 голосов
/ 07 ноября 2018

Я хочу добавить / удалить в список, но я получил исключение «Индекс вне диапазона». В моем коде я добавляю данные 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 голосов
/ 07 ноября 2018

Проблема 1: вы разрешаете 3 одновременным потокам для доступа к списку, должен быть новый семафор (1, 1);

Проблема 2: sem.Release () никогда не вызывается (недоступный код из-за while (true)), поэтому вы должны переместить sem.WaitOne (), чтобы быть первым оператором внутри, а блок и sem.Release (), чтобы быть последняя строка внутри блока

Рабочий код:

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();
        }
    }
}
0 голосов
/ 07 ноября 2018

Вы разрешаете запускать три потока одновременно:

new Semaphore(3, 3);

Значит, ваш Semaphore не очень вам помогает, потому что вы на самом деле не блокируете. Таким образом, у вас все еще есть проблема, когда, например, вы можете оставить одно сообщение в списке, но все 3 потока оценивают messagesList.Count > 0 как true. Один из этих потоков сначала удалит элемент из списка, что приведет к тому, что другие два сгенерируют исключение.

Есть лучшие способы сделать это. Для списков мне нравится использовать ReaderWriterLockSlim, который имеет блокировки чтения и записи. Он позволяет читать все потоки, но блокирует всех, как только вы блокируете запись. Вот пример того, как использовать это в документации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...