This question has already been answered:

As part of the independent study of cryptography, I wrote a program that calculates the hash function of the file. Faced the problem that this program is slow on large files. I decided to use threads (Threads) to process and calculate in separate threads. I created threads, passed methods, NullReferenceException is triggered - an object reference is not specified in the object instance. I after all initialized all variables in all methods. What could be the problem?

I attach the full code of the main class. Please comment on the code and point out my mistakes. Thank.

 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); } } } 

Reported as a duplicate by members Pavel Mayorov , user194374, Grundy , αλεχολυτ , Ivan Pshenitsyn Aug 26 '16 at 22:10 .

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

  • Well, actually everything is logical: hash is filled in one stream, and is read in another, and apparently it reads before it is filled - Grundy
  • "apparently reads before it is filled" - judging by what? how to define it? - AlexPetr_98
  • by the fact that at the moment of reading from this variable it is still null - Grundy
  • and what is the meaning of Thread.Sleep(100); at the end of the functions? - Grundy
  • oh, it turns out to be much worse here: in the loop, the same hash and buf variables are used in the threads - Grundy

1 answer 1

Here is the code that works:

 using System; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; namespace TestHash { class Program { private FileInfo file; private FileStream fileStream; 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 void Run() { string path, s; var sha256 = new SHA256Managed(); 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; var buf = new byte[messageLength]; fileStream.Read(buf, 0, buf.Length); ThreadPool.QueueUserWorkItem((obj) => { PrintBlocks(sha256.ComputeHash(buf)); }); } fileStream.Close(); } /// <summary> /// Печатаем блоки: /// </summary> private void PrintBlocks(byte[] hash) { for (int i = 0; i < hash.Length; i++) Console.Write("{0}-й блок: {1:X2} ", i + 1, hash[i]); Console.WriteLine(); } } } 

but I can immediately say that the results of the time measurement will be incorrect, since run is completed before all other threads are completed. I think you should take a look at thread synchronization.