none
Сжатие и расжатие файлов GZipStream RRS feed

  • Вопрос

  • Здравствуйте! Пишу программу для сжатия файлов. Столкнулся со следующей ситуацией. Программа вычисляет количесто процессоров в системе. Затем, в зависимости от их количества создает пропорциональное количество потоков. Создается пул потоков. Поток тред читает из потока и начинает сжатие. Тоже самое делают и другие потоки. В определенный момент возникает исключение System.InvalidOperationException. Причем вываливается оно при запси методом Write. Ниже приведен фрагмент в котором это происходит. Подскажите пожалуйста из-за чего это может быть. Вроде бы потоки синхронизированы. Спасибо!

    using (ManualResetEvent mre = new ManualResetEvent(false))
                {
                    for (int p = 0; p < numProcs; p++)
                    {
                        long start = p * range + from;
                        long end = (p == numProcs - 1) ? to : start + range;
    
                        ThreadPool.QueueUserWorkItem(delegate
                        {
                            byte[] b = new byte[buffer_size];
                            int bytesRead;
    
                            while ((bytesRead = fs.Read(b, 0, buffer_size)) > 0)
                            {
                                Console.WriteLine("Pos = {0}", fs.Position);
                                gzs.Write(b, 0, bytesRead);
                                Array.Clear(b, 0, bytesRead);
                            }
    
                                if (Interlocked.Decrement(ref remaining) == 0)
                                    mre.Set();
                        });
                    }
                    mre.WaitOne();
                }

    • Перемещено ЖукMVP, Moderator 11 мая 2013 г. 13:23 более подходящий раздел

Ответы

  • На эти параметры внимания можете не обращать. Как не видно синхронизации? А разве ManualResetEvent и методы Set и WaiteOne не используются для синхронизации?
    Да, основной поток будет ждать пока не завершатся задания в ThreadPool, однако сами задания никак не синхронизируются между собой и могут выполнятся одновременно, В частности данная команда:
    gzs.Write(b, 0, bytesRead);
    может выполнятся одновременно в нескольких потоках, в то время как в описании класса GZipStream сказано:
    Any instance members are not guaranteed to be thread safe.
    • Помечено в качестве ответа KazunEditor 14 мая 2013 г. 8:03

Все ответы

  • Освежите память внимательно прочитав статью http://msdn.microsoft.com/ru-ru/library/system.invalidoperationexception.aspx

    При создании вопроса, обращайте внимание на раздел, где Вы размещаете свой вопрос ;)


    Да, я Жук, три пары лапок и фасеточные глаза :))

    Модератор
  • Спасибо, конечно, но я это читал. Я понял почему так происходит. Я прошу пояснить как такое может быть, что gzs может быть в таком состоянии, что нельзя писать. В какой моент времени это происходит? Одновременно потоки не могут это делать так как я их синхронизирую. Возможно я не правильно это делаю. Пясните пожалуйста.
  • Не обессудьте, перенёс Ваш вопрос, в более подходящий раздел ;)

    Да, я Жук, три пары лапок и фасеточные глаза :))

    Модератор
  • Такое ощущение, что не весь код приведён: непонятные переменные start и end которые никак не используются. А также не видно синхронизации потоков, о которой Вы говорите.
  • На эти параметры внимания можете не обращать. Как не видно синхронизации? А разве ManualResetEvent и методы Set и WaiteOne не используются для синхронизации?
  • На эти параметры внимания можете не обращать. Как не видно синхронизации? А разве ManualResetEvent и методы Set и WaiteOne не используются для синхронизации?
    Да, основной поток будет ждать пока не завершатся задания в ThreadPool, однако сами задания никак не синхронизируются между собой и могут выполнятся одновременно, В частности данная команда:
    gzs.Write(b, 0, bytesRead);
    может выполнятся одновременно в нескольких потоках, в то время как в описании класса GZipStream сказано:
    Any instance members are not guaranteed to be thread safe.
    • Помечено в качестве ответа KazunEditor 14 мая 2013 г. 8:03
  • Спасибо огромное! Очень помог. Использую мьютексы - все работает отлично. А  есть идеи как можно файлы больших размеров обрабатывать? Я Подаю на вход файл в 9Гб. Он сначала все правильно делает, а потом, видимо ему не хватает памяти и он выдает об этом ексепшен. Эффективный ли будет вариант разбивать исходный файл на файлы поменьше?
  • Сам я никогда с GZipStream не работал, возможно там просто техническое ограничение алгоритма сжатия на размер входных данных. Тут надо смотреть само исключение. По идее, с точки зрения сжатия, лучше пихать всё одним куском, чем разбивать на части.