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;
}
}
}
main
into the same block of code. Simplify to handling the least derived type,Exception
in this case. \$\endgroup\$