Conversation
MyThreadPool/MyThreadPool/IMyTask.cs
Outdated
| /// <summary> | ||
| /// A method for solving subtasks from the results obtained from the tasks | ||
| /// </summary> | ||
| public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler); |
There was a problem hiding this comment.
Комментарии должны присутствовать у всех public-методов, а не выборочно :)
MyThreadPool/MyThreadPool/IMyTask.cs
Outdated
| /// <summary> | ||
| /// A method for solving subtasks from the results obtained from the tasks | ||
| /// </summary> | ||
| public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler); |
| private readonly CancellationTokenSource token = new(); | ||
| private readonly Object lockerForThreads; | ||
| private readonly Object lockerForTasks; | ||
| private volatile bool stopCount = false; |
There was a problem hiding this comment.
Компилятор ругается, что значение поля нигде не используется
| /// Accepts a function, adds it as a task in the thread, and returns the created task | ||
| /// </summary> | ||
| public IMyTask<TResult> Submit<TResult>(Func<TResult> suppiler) | ||
| { |
There was a problem hiding this comment.
Здесь надо учесть условие "после вызова Shutdown новые задачи не принимаются на исполнение потоками из пула", а также согласовать исполнение метод с Shutdown (сделать так, чтобы не было гонок при вызове Submit и Shutdown одновременно из разных потоков)
There was a problem hiding this comment.
Согласование Submit с Shutdown -- не готово.
(для этого надо использовать lock по защищаемому ресурсу)
| if (token.IsCancellationRequested) | ||
| { | ||
| ; | ||
| } |
There was a problem hiding this comment.
Видимо, поле stopCount создавалось как показатель, был ли уже запрошен Shutdown. Тогда надо его либо свойством сделать, либо вообще убрать. Если свойством сделать, то у stopCount будет хоть какое-то гипотетическое применение в виде запрашивания извне.
И назвать тогда как-то понятнее, типо IsShutdownRequested
MyThreadPool/MyThreadPool/MyTask.cs
Outdated
| isCompleted = true; | ||
| while (queueWithContinueWithTasks.Count > 0) | ||
| { | ||
| queueWithTasks.Enqueue(queueWithContinueWithTasks.Dequeue()); |
There was a problem hiding this comment.
По-хорошему, напрямую с очередью должен работать только пул и его треды. Task - это уже другой уровень абстракции, он лишь вызывает методы треда типо Submit. Поэтому здесь надо переписать через Submit треда
MyThreadPool/MyThreadPool/MyTask.cs
Outdated
| private volatile bool isCompleted = false; | ||
| private TResult? result; | ||
| private readonly Queue<Action> queueWithContinueWithTasks; | ||
| private readonly MyThread[] arrayThreads; |
MyThreadPool/MyThreadPool/MyTask.cs
Outdated
| } | ||
|
|
||
| public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler) | ||
| { |
There was a problem hiding this comment.
Здесь тоже прямую работу с очередью задач пула надо заменить на Submit. Иначе если кто-угодно будет его очередь менять, сложно будет найти ошибку. Да и не в духе ООП это
MyThreadPool/MyThreadPool/MyTask.cs
Outdated
| } | ||
|
|
||
| public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler) | ||
| { |
There was a problem hiding this comment.
Здесь тоже надо позаботиться об отсутствии гонок между ContinueWith и Shutdown, между добавлением continuation-ов на пул и Shutdown (используя lock(и))
| Assert.That(Equals(myTask.Result, "16")); | ||
| myThreadPool.Shutdown(); | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Тестов стоит добавить: тест, проверяющий, что в пуле действительно не менее n потоков; тест на корректность IsCompleted, Result (в случае с исключением); тест на Shutdown (проверить, что "уже запущенные задачи не прерываются, но новые задачи не принимаются на исполнение потоками из пула"); тесты на конкурентный доступ к методам пула из нескольких потоков (submit задач из разных потоков, Submit и Shutdown одновременно)
YuriUfimtsev
left a comment
There was a problem hiding this comment.
Уже лучше, но исправлено не всё. И куда-то исчез механизм работы с continuation-ами задач
| if (token.IsCancellationRequested) | ||
| { | ||
| return; | ||
| } |
| /// Accepts a function, adds it as a task in the thread, and returns the created task | ||
| /// </summary> | ||
| public IMyTask<TResult> Submit<TResult>(Func<TResult> suppiler) | ||
| { |
There was a problem hiding this comment.
Согласование Submit с Shutdown -- не готово.
(для этого надо использовать lock по защищаемому ресурсу)
|
|
||
| if (!token.IsCancellationRequested) | ||
| { | ||
| return pool.Submit(() => supplier(Result)); |
There was a problem hiding this comment.
Ниже компилятор ругается: действительно, почему supplier может быть null?
| waitHandle.WaitOne(); | ||
| if (!token.IsCancellationRequested) | ||
| { | ||
| lock (locker) |
There was a problem hiding this comment.
Здесь lock по очереди задач надо, как ранее писал
| /// <summary> | ||
| /// A method for solving subtasks from the results obtained from the tasks | ||
| /// </summary> | ||
| public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> supplier) |
There was a problem hiding this comment.
Здесь и в StartSupplier куда-то пропала функциональность по добавлению всех continuation-ов в очередь и сабмиту этих continuation-ов в тредпул, когда "базовая" задача досчиталась. А это для выполнения условий задачи важно
| Assert.That(firstTask.Result, Is.EqualTo(4)); | ||
| Assert.That(secondTask.Result, Is.EqualTo(6)); |
There was a problem hiding this comment.
А вот это хорошо, никаких Assert.That(Equals(..)) 👍
| private TResult? result; | ||
| private Exception? exception; | ||
| private CancellationTokenSource token; | ||
| private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); |
There was a problem hiding this comment.
Эквивалентно
| private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); | |
| private ManualResetEvent resetEvent = new ManualResetEvent(false); |
Удобнее использовать и более распространено :)
Для пропуска одного потока, а не всех сразу, есть AutoResetEvent
| /// </summary> | ||
| public MyThreadPool(int sizeThreads) | ||
| { | ||
| waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); |
There was a problem hiding this comment.
Здесь тоже лучше ManualResetEvent использовать. Хотя если вы его используйте для пропуска одного потока для выполнения задачи при Submit, то лучше AutoResetEvent. MRE только все потоки умеет пропускать за раз
|
|
||
| [Test] | ||
| public void NumberThreadsTheRequiredNumberIsCreated() | ||
| { |
There was a problem hiding this comment.
Не, так просто не получится. Вдруг GetNumberOfThreads просто заданное число возвращает :)
Здесь надо загрузить все потоки пула задачами и проверить, что новая добавленная задача не будет принята на исполнение. Для того, чтобы загрузить потоки задачами, внутри задач можно использовать ManualResetEvent
|
|
||
| using MyThreadPool; | ||
|
|
||
| public class Tests |
There was a problem hiding this comment.
Тестов на конкурентный доступ к методам пула по-прежнему не хватает
No description provided.