diff --git a/ThreadPool/ThreadPool.sln b/ThreadPool/ThreadPool.sln
new file mode 100644
index 0000000..9bef84d
--- /dev/null
+++ b/ThreadPool/ThreadPool.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreadPool", "ThreadPool\ThreadPool.csproj", "{E0D93E78-090C-4C9B-B545-DBB1534BC37D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreadPoolTest", "ThreadPoolTest\ThreadPoolTest.csproj", "{AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E0D93E78-090C-4C9B-B545-DBB1534BC37D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE21AEB8-EC3E-4D26-A154-E8C11BA4F93E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/ThreadPool/ThreadPool/IMyTask.cs b/ThreadPool/ThreadPool/IMyTask.cs
new file mode 100644
index 0000000..6ee16d4
--- /dev/null
+++ b/ThreadPool/ThreadPool/IMyTask.cs
@@ -0,0 +1,25 @@
+namespace ThreadPool;
+
+using System;
+
+///
+/// interface for object from MyThreadPool
+///
+public interface IMyTask
+{
+ ///
+ /// shows whether the task is completed or not
+ ///
+ public bool IsCompleted { get; set; }
+
+ ///
+ /// returns the result of the task
+ ///
+ public TResult Result { get; }
+
+ ///
+ /// continues calculating
+ ///
+ public IMyTask ContinueWith(Func func);
+}
+
diff --git a/ThreadPool/ThreadPool/MyThreadPool.cs b/ThreadPool/ThreadPool/MyThreadPool.cs
new file mode 100644
index 0000000..f22dac4
--- /dev/null
+++ b/ThreadPool/ThreadPool/MyThreadPool.cs
@@ -0,0 +1,208 @@
+namespace ThreadPool;
+
+using System.Collections.Generic;
+using System.Threading;
+using System.Collections.Concurrent;
+using System;
+
+///
+/// pool of threads that can be used to execute tasks
+///
+public class MyThreadPool
+{
+ private readonly Thread[] _threads;
+ private readonly CancellationTokenSource _token = new();
+ private readonly ConcurrentQueue _tasksQueue = new();
+ private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false);
+ private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false);
+ private volatile int _freeThreadsCount = 0;
+ private readonly object _lockObject = new();
+
+ ///
+ /// constructor
+ ///
+ public MyThreadPool(int countThreads)
+ {
+ if (countThreads < 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(countThreads));
+ }
+
+ _threads = new Thread[countThreads];
+ for (int i = 0; i < countThreads; i++)
+ {
+ _threads[i] = new Thread(() =>
+ {
+ while (!_token.IsCancellationRequested || !_tasksQueue.IsEmpty)
+ {
+ if (_tasksQueue.TryDequeue(out Action action))
+ {
+ action();
+ }
+ else
+ {
+ _waiterNewTask.WaitOne();
+ if (!_tasksQueue.IsEmpty)
+ {
+ _waiterNewTask.Set();
+ }
+ }
+ }
+
+ Interlocked.Increment(ref _freeThreadsCount);
+ _waiterTaskDone.Set();
+ });
+
+ _threads[i].Start();
+ }
+ }
+
+ ///
+ /// add task
+ ///
+ public IMyTask AddTask(Func function)
+ {
+ ReadyToAddNewTask();
+ lock (_lockObject)
+ {
+ ReadyToAddNewTask();
+ var task = new MyTask(function, this);
+ AddInTaskQueue(task.Count);
+ return task;
+ }
+ }
+
+ private void ReadyToAddNewTask()
+ {
+ if (_token.IsCancellationRequested)
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ private void AddInTaskQueue(Action task)
+ {
+ _tasksQueue.Enqueue(task);
+ _waiterNewTask.Set();
+ }
+
+ ///
+ /// close threads
+ ///
+ public void Shutdown()
+ {
+ lock (_lockObject)
+ {
+ _token.Cancel();
+ }
+
+ while (_freeThreadsCount != _threads.Length)
+ {
+ _waiterNewTask.Set();
+ _waiterTaskDone.WaitOne();
+ }
+ }
+
+ ///
+ /// class for parallel tasks
+ ///
+ private class MyTask : IMyTask
+ {
+ private Func _func;
+ private TResult _result;
+ private Exception _resultException = null;
+ private readonly object _locker = new();
+ private readonly ManualResetEvent _waiterManual = new(false);
+ private Queue _continueWithTasksQueue = new();
+ private readonly MyThreadPool _myThreadPool;
+
+ ///
+ /// shows whether the task is completed or not
+ ///
+ public bool IsCompleted { get; set; }
+
+ ///
+ /// returns the result of the task
+ ///
+ public TResult Result
+ {
+ get
+ {
+ _waiterManual.WaitOne();
+ if (_resultException != null)
+ {
+ throw new AggregateException(_resultException);
+ }
+
+ return _result;
+ }
+ }
+
+ ///
+ /// constructor
+ ///
+ public MyTask(Func function, MyThreadPool myThreadPool)
+ {
+ ArgumentNullException.ThrowIfNull(function);
+ _func = function;
+ _myThreadPool = myThreadPool;
+ }
+
+ ///
+ /// counting result of task
+ ///
+ public void Count()
+ {
+ try
+ {
+ _result = _func();
+ }
+ catch (Exception funcException)
+ {
+ _resultException = funcException;
+ }
+
+ lock (_locker)
+ {
+ _func = null;
+ IsCompleted = true;
+ _waiterManual.Set();
+ }
+
+ lock (_locker)
+ {
+ while (_continueWithTasksQueue.Count > 0)
+ {
+ var action = _continueWithTasksQueue.Dequeue();
+ lock (_myThreadPool._lockObject)
+ {
+ _myThreadPool.AddInTaskQueue(action);
+ }
+ }
+ }
+ }
+
+ ///
+ /// continues calculating
+ ///
+ public IMyTask ContinueWith(Func func)
+ {
+ lock (_myThreadPool._lockObject)
+ {
+ _myThreadPool.ReadyToAddNewTask();
+ var task = new MyTask(() => func(Result), _myThreadPool);
+ _continueWithTasksQueue.Enqueue(task.Count);
+ if (IsCompleted)
+ {
+ while (_continueWithTasksQueue.Count > 0)
+ {
+ var action = _continueWithTasksQueue.Dequeue();
+ _myThreadPool._tasksQueue.Enqueue(action);
+ _myThreadPool._waiterNewTask.Set();
+ }
+ }
+ return task;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ThreadPool/ThreadPool/ThreadPool.csproj b/ThreadPool/ThreadPool/ThreadPool.csproj
new file mode 100644
index 0000000..6a038c2
--- /dev/null
+++ b/ThreadPool/ThreadPool/ThreadPool.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net6.0
+ Windows
+ 10
+ disable
+
+
+
diff --git a/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs
new file mode 100644
index 0000000..33f916e
--- /dev/null
+++ b/ThreadPool/ThreadPoolTest/ThreadPoolTest.cs
@@ -0,0 +1,207 @@
+namespace ThreadPoolTest;
+
+using System;
+using System.Threading;
+using NUnit.Framework;
+using ThreadPool;
+
+public class Tests
+{
+ private MyThreadPool _threadPool;
+ private readonly int _numberOfThreads = 4;
+
+ [SetUp]
+ public void Setup()
+ => _threadPool = new(Environment.ProcessorCount);
+
+ [TearDown]
+ public void TearDown()
+ => _threadPool.Shutdown();
+
+ [Test]
+ public void NullFunctionShouldThrowException()
+ {
+ Assert.Throws(() => _threadPool.AddTask