2

В рамках самостоятельного изучения криптограифии написал программу, которая вычисляет хэш-функцию файла. Столкнулся с проблемой, что на больших файлах эта программа работает медленно. Я решил использовать потоки (Threads), чтобы обработка и вычисление выполнялись в отдельных потоках. Потоки я создал, методы передал, срабатывает NullReferenceException - в экземпляре объекта не задана ссылка на объект. Я ведь инициализировал все переменные во всех методах. В чем может быть проблема?

Прикрепляю полный код главного класса. Прошу прокомментировать код и указать на мои ошибки. Спасибо.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace SHA_256
{
    internal class Program
    {
        private byte[] buf;
        private SHA256 sha256;
        private uint[] hash;

        private static void Main(string[] args)
        {
            Program program = new Program();
            Stopwatch stopWatch = new Stopwatch();
            stopWatch.Start();
            program.Run();
            stopWatch.Stop();
            TimeSpan ts = stopWatch.Elapsed;
            string elapsedTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            Console.WriteLine("Время работы:  " + elapsedTime);
            Console.ReadKey();
        }

        private FileInfo file;
        private FileStream fileStream;

        private void Run()
        {
            string path, s;
            sha256 = new SHA256();

            Console.WriteLine("Введите путь к файлу:");
            path = Console.ReadLine();

            Console.WriteLine("Введите размер блока:"); // чем больше, тем меньшими "порциями" обрабатывается файл,
                                                        // но в итоге время работы программы остается прежним
            s = Console.ReadLine();
            uint numBlocks = uint.Parse(s);

            file = new FileInfo(path);
            fileStream = file.Open(FileMode.Open);

            long len = fileStream.Length;
            long messageLength = len / numBlocks;

            for (int i = 0; i < numBlocks; i++)
            {
                fileStream.Position = i;
                buf = new byte[messageLength];
                fileStream.Read(buf, 0, buf.Length);

                // вычисляем хэш для данного блока:
                Thread th1 = new Thread(delegate () { ComputeHash(buf); });
                th1.Start();
                // печатаем блоки:
                Thread th2 = new Thread(delegate () { PrintBlocks(hash); });
                th2.Start();

                // да еще такой вопрос - надо ли освобождать вручную память
                // после использования массива buf[] (он ведь больше не нужен)?
                // в C++ я это делал обязательно, а в C# как?
            }
            fileStream.Close();
        }

        /// <summary>
        /// Вычисляем хэш-функцию SHA256 для заданного блока:
        /// и вообще можно ли считать хэш-функцию ДЛЯ БЛОКА(!!!) файла
        /// а не для ВСЕГО файла
        /// </summary>
        /// <param name="message"></param>
        /// <param name="size"></param>
        private void ComputeHash(byte[] message)
        {
            hash = sha256.ComputeHash(message);
            Thread.Sleep(100);
        }

        /// <summary>
        /// Печатаем блоки:
        /// </summary>
        private void PrintBlocks(uint[] hash)
        {
            for (int i = 0; i < hash.Length; i++)
            {
                Console.Write("{0}-й блок: {1:X2} ", i + 1, hash[i]);
            }
            Console.WriteLine();
            Thread.Sleep(100);
        }
    }
}
andreycha
  • 25,167
  • 4
  • 46
  • 82
  • ну собственно все логично: hash заполняется в одном потоке, а читается в другом, и судя по всему читается раньше чем заполнилось – Grundy Aug 25 '16 at 21:41
  • "судя по всему читается раньше чем заполнилось" - судя по чему? как это определить? – AlexPetr_98 Aug 25 '16 at 21:51
  • по тому что в момент чтения из этой переменной она все еще null – Grundy Aug 25 '16 at 22:12
  • а в чем смысл Thread.Sleep(100); в конце функций? – Grundy Aug 25 '16 at 22:13
  • о, оказывается тут все намного хуже: в цикле в потоках используются одни и те же переменные hash и buf – Grundy Aug 25 '16 at 22:15
  • ясно. но что-то пока ничего другое не придумать.
  • – AlexPetr_98 Aug 25 '16 at 22:29
  • по сути ведь Thread.Sleep(100) приостанавливает поток на указанное время.
  • – AlexPetr_98 Aug 25 '16 at 22:30
  • да я не сомневаюсь, что все плохо - только ведь начал изучать эту тему.
  • – AlexPetr_98 Aug 25 '16 at 22:31