I making simple multithreading signature program (it calculate SHA256 hash for parts of file). Please check my code and I would be grateful if you tell me about errors in my code

**Program.cs**

```
using System;
using System.IO;

namespace Signature
{
    class Program
    {
        public static TaskQueue Tasks;
        public static HashPrinter Printer;

        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine("You must specify two parameters. Example: Signature.exe [filename] [chunkSize]");
                return;
            }
            var filename = args[0];
            int chunk;
            if (!int.TryParse(args[1], out chunk))
            {
                Console.WriteLine("You shoul specify number as [chunkSize]");
                return;
            }
            try
            {
                Tasks = new TaskQueue(Environment.ProcessorCount);
                Printer = new HashPrinter(200000);
                var reader = new FileReader(filename, chunk);
                reader.Read();
            }
            catch (IndexOutOfRangeException ex)
            {
                PrintError(ex.Message, ex.StackTrace);
            }
            catch (FileNotFoundException ioException)
            {
                PrintError(ioException.Message, ioException.StackTrace);
            }
            catch (DirectoryNotFoundException ioException)
            {
                PrintError(ioException.Message, ioException.StackTrace);
            }
            catch (IOException ioException)
            {
                PrintError(ioException.Message,ioException.StackTrace);
            }
            catch (Exception err)
            {
                PrintError(err.Message,err.StackTrace);
            }
            Console.ReadLine();
        }

        private static void PrintError(string message,string trace)
        {
            Console.WriteLine(message);
            Console.WriteLine(trace);
        }
    }
}

```

**TaskQueue.cs**

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Signature
{
    internal class TaskQueue : IDisposable
    {
        private readonly object _locker = new object();
        private readonly Thread[] _threads;
        private readonly int _threadsCount;
        private Queue<KeyValuePair<long, byte[]>> _tasks = new Queue<KeyValuePair<long, byte[]>>();

        public TaskQueue(int threadsCount)
        {
            if (threadsCount <= 0)
                throw new IndexOutOfRangeException("Processor count should be positive");
            _threadsCount = threadsCount;
            _threads = new Thread[threadsCount];
            for (var i = 0; i < threadsCount; i++)
            {
                _threads[i] = new Thread(Consume) { IsBackground = false };
                _threads[i].Start();
            }
        }

        public void Dispose()
        {
            for (var i = 0; i < _threadsCount; i++)
            {
                AddTask(new KeyValuePair<long, byte[]>(-1, new byte[0]));
            }
            for (var i = 0; i < _threadsCount; i++)
            {
                _threads[i].Join();
            }
            Program.Printer.Dispose();
        }

        public void AddTask(KeyValuePair<long, byte[]> task)
        {
            lock (_locker)
            {
                _tasks.Enqueue(task);
                Monitor.Pulse(_locker);
            }
        }

        public string ByteArrayToString(byte[] array)
        {
            StringBuilder sb = new StringBuilder();
            int i;
            for (i = 0; i < array.Length; i++)
            {
                sb.Append($"{array[i]:X2}");
                if ((i % 4) == 3) sb.Append(" ");
            }
            return sb.ToString();
        }

        private void Consume()
        {
            while (true)
            {
                KeyValuePair<long, byte[]> task = new KeyValuePair<long, byte[]>();
                lock (_locker)
                {
                    while (!_tasks.Any())
                    {

                        Monitor.Wait(_locker);
                    }
                    task = _tasks.Dequeue();
                   }
                if (task.Key == -1)
                {
                    return;
                }
                Program.Printer.AddHashPart(new KeyValuePair<long, byte[]>(task.Key,ShaCreator.ComputeHash(task.Value)));
            }
        }
    }
}

```

**FileReader.cs**

```
using System;
using System.Collections.Generic;
using System.IO;

namespace Signature
{
    internal class FileReader
    {
        private readonly FileStream _inputFileStream;
        private readonly int _chunkSize;

        public FileReader(string filename, int chunkSize)
        {
            try
            {
                _inputFileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            }
            catch (FileNotFoundException ioException)
            {
                throw new FileNotFoundException("File not found",ioException);
            }
            catch (DirectoryNotFoundException ioException)
            {
                throw new DirectoryNotFoundException("Directory not found",ioException);
            }
            catch (IOException ioException)
            {
                throw new IOException("IO error",ioException);
            }
            _chunkSize = chunkSize;
        }

        ~FileReader()
        {
            if (_inputFileStream != null)
            {
                _inputFileStream.Close();
            }
        }

        public void Read()
        {
            var buffer = new byte[_chunkSize];
            var bytesRead = 0;
            _inputFileStream.Seek(0, SeekOrigin.Begin);
            bytesRead = _inputFileStream.Read(buffer, 0, _chunkSize);
            long partNum = 1;
            Program.Tasks.AddTask(new KeyValuePair<long, byte[]>(partNum, buffer));
            while (bytesRead > 0)
            {
                partNum++;
                buffer = new byte[_chunkSize];
                bytesRead = _inputFileStream.Read(buffer, 0, _chunkSize);
                if (bytesRead != 0)
                {
                    if (bytesRead < _chunkSize)
                    {
                        Array.Resize(ref buffer,bytesRead);
                    }
                    Program.Tasks.AddTask(new KeyValuePair<long, byte[]>(partNum, buffer));
                }
            }
            Program.Tasks.Dispose();
        }
    }
}

```

**HashPrinter.cs**

```
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Text;
using System.Threading;

namespace Signature
{

    internal class HashPrinter : IDisposable
    {
        private readonly object _locker = new object();
        private readonly Thread _threadPrint;
        private readonly List<KeyValuePair<long, byte[]>> _hashList = new List<KeyValuePair<long, byte[]>>();
        private readonly int _maxListSize;
        private long _currentPrint = 1;

        public HashPrinter(int maxListSize)
        {
            if (maxListSize <= 0)
                throw new IndexOutOfRangeException("Max size should be positive");
            _maxListSize = maxListSize;
            _threadPrint = new Thread(Consume) { IsBackground = false };
            _threadPrint.Start();
        }

        public void Dispose()
        {
            AddHashPart(new KeyValuePair<long, byte[]>(-1, new byte[0]));
            _threadPrint.Join();

        }

        public void AddHashPart(KeyValuePair<long, byte[]> hashPart)
        {
            lock (_locker)
            {
                while (_hashList.Count >= _maxListSize)
                {
                    Monitor.Wait(_locker,10);
                }
                if (hashPart.Key == -1)
                {
                    Sort();
                }
                _hashList.Add(hashPart);
                Monitor.Pulse(_locker);
            }
        }

        private void Sort()
        {
            _hashList.Sort(Compare);
        }

        private int Compare(KeyValuePair<long, byte[]> a, KeyValuePair<long, byte[]> b)
        {
            return a.Key.CompareTo(b.Key);
        }

        public string ByteArrayToString(byte[] array)
        {
            StringBuilder sb = new StringBuilder();
            int i;
            for (i = 0; i < array.Length; i++)
            {
                sb.Append($"{array[i]:X2}");
                if ((i % 4) == 3) sb.Append(" ");
            }
            return sb.ToString();
        }

        private void Consume()
        {
            while (true)
            {
                KeyValuePair<long, byte[]> part;
                lock (_locker)
                {
                    while (_hashList.Count == 0)
                    {
                        Monitor.Wait(_locker);
                    }
                    part = _hashList[0];
                    if (part.Key == -1)
                    {
                        return;
                    }
                    if (part.Key == _currentPrint)
                    {
                        _currentPrint++;
                        Console.WriteLine("Part #{0}, Hash: {1}", part.Key, ByteArrayToString(part.Value));
                        //lock (_locker)
                        //{
                            _hashList.Remove(part);
                        //}
                    }
                    else
                    {
                        //lock (_locker)
                        Sort();// }
                    }
                }

            }
        }
    }
}

```

**SHACreator.cs**

```
using System.Security.Cryptography;

namespace Signature
{
    internal class ShaCreator
    {
        public static byte[] ComputeHash(byte[] dataBytes)
        {
            SHA256 mSha256 = SHA256Managed.Create();
            var hashValue = mSha256.ComputeHash(dataBytes);
            return hashValue;
        }
    }
}

```