Conversation
ThreadPool/ThreadPool/IMyTask.cs
Outdated
| namespace ThreadPool | ||
| { | ||
| /// <summary> | ||
| /// task interface |
There was a problem hiding this comment.
Понятно что это интерфейс, но что это за интерфейс?
ThreadPool/ThreadPool/MyTask.cs
Outdated
| namespace ThreadPool | ||
| { | ||
| /// <summary> | ||
| /// task classs |
There was a problem hiding this comment.
Тоже не очень, даже более не очень, чем в предыдущем случае :)
ThreadPool/ThreadPool/MyTask.cs
Outdated
| /// <summary> | ||
| /// task classs | ||
| /// </summary> | ||
| public class MyTask<TResult> : IMyTask<TResult> |
There was a problem hiding this comment.
Его лучше сделать private- вложенным классом для MyThreadPool, чтобы у пользователей не было соблазна создавать его самому, вызывать Count и делать прочие ненужные вещи.
ThreadPool/ThreadPool/MyTask.cs
Outdated
| /// </summary> | ||
| public MyTask(Func<TResult> function) | ||
| { | ||
| _func = function ?? throw new ArgumentException(); |
There was a problem hiding this comment.
Можно более специфично, ArgumentNullException(nameof(function));
ThreadPool/ThreadPool/MyTask.cs
Outdated
| _resultException = funcException; | ||
| } | ||
|
|
||
| lock (_locker) |
There was a problem hiding this comment.
Это, как я понимаю, задел на будущее, потому что пока синхронизироваться не с кем
| { | ||
| if (countThreads < 1) | ||
| { | ||
| throw new ArgumentException(); |
There was a problem hiding this comment.
ArgumentOutOfRangeException(nameof(countThreads));
| } | ||
|
|
||
| var task = new MyTask<TResult>(function); | ||
| _tasksQueue.Enqueue(task.Count); |
There was a problem hiding this comment.
Не-а, если в этот момент сделают Shutdown и остановят все треды, задача добавится в очередь, но делать её будет некому. Получится задача-зомби --- она как бы жива, но не работает, и любой, кто вызовет её Result, задедлочится
| lock (_lockObject) | ||
| { | ||
| _token.Cancel(); | ||
| } |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
ThreadPool/ThreadPool/Program.cs
Outdated
| static void Main(string[] args) | ||
| { | ||
| Console.WriteLine("Hello World!"); | ||
| } |
There was a problem hiding this comment.
Это не нужно, собирайте библиотеку просто
| _threadPool.AddTask(() => | ||
| { | ||
| Interlocked.Increment(ref number); | ||
| Thread.Sleep(3000); |
There was a problem hiding this comment.
Для этого есть всякие ManualResetEvent-ы, а то очень долго тесты исполняться будут
| } | ||
| } | ||
|
|
||
| var task = new MyTask<TResult>(function, this); |
There was a problem hiding this comment.
Мм, и в этот момент происходит Shutdown, все потоки останавливаются, но мы уже не можем отменить добавление таска.
| while (_continueWithTasksQueue.Count > 0) | ||
| { | ||
| var action = _continueWithTasksQueue.Dequeue(); | ||
| lock (_locker) |
There was a problem hiding this comment.
Двойной lock на _locker? Если бы lock в C# был не рекурсивным, был бы дедлок :) Может, имелся в виду lockObject из тредпула? Но тогда доверили бы тредпулу им управлять
| lock (_locker) | ||
| { | ||
| _myThreadPool._tasksQueue.Enqueue(action); | ||
| _waiterManual.Set(); |
There was a problem hiding this comment.
Он и так выставлен тут уже. Или, опять-таки, имелся в виду флаг из тредпула?
|
|
||
| var task = new MyTask<TNewResult>(() => func(Result), _myThreadPool); | ||
| _continueWithTasksQueue.Enqueue(task.Count); | ||
| if (IsCompleted) |
There was a problem hiding this comment.
Если IsCompleted, можно просто добавлять таск на тредпул, даже лочить никого не надо. О задачах из очереди позаботится Count. А то тут как-то очень много всего в критической секции.
yurii-litvinov
left a comment
There was a problem hiding this comment.
Надо ещё немного поправить
|
|
||
| namespace ThreadPool | ||
| { | ||
| public class MyThreadPool |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| } | ||
| lock (_lockObject) | ||
| { | ||
| var task = new MyTask<TResult>(function, this); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| lock (_myThreadPool._lockObject) | ||
| { | ||
| _myThreadPool._tasksQueue.Enqueue(action); | ||
| _myThreadPool._waiterNewTask.Set(); | ||
| } |
There was a problem hiding this comment.
Это лучше доверить самому тредпулу. И это не синхронизировано с Shutdown, так что хоть, кажется, и будет работать (потому что у Вас потоки останавливаются только когда очередь пуста, а тут она гарантированно не пуста, потому что какой-то поток нас сейчас как раз и считает на 39-й строчке, и мы ему ещё задач накидаем), но это ни разу не очевидно и стоило хотя бы в комментарии написать.
| { | ||
| throw new InvalidOperationException(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Лучше сделайт требпулу приватный метод "Готов принимать новые задачи" и вызывайте его тут и в AddTask. А то это какое-то вмешательство в личную жизнь
| } | ||
| } | ||
|
|
||
| var task = new MyTask<TNewResult>(() => func(Result), _myThreadPool); |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| Assert.AreEqual(16, task2.Result); | ||
| Assert.AreEqual(28, task3.Result); | ||
| } | ||
| } |
There was a problem hiding this comment.
Надо бы ещё тесты на параллельные запросы к тредпулу (например, Shutdown и AddTask, что ничего не дедлочится)
There was a problem hiding this comment.
Всё ещё нужно. Кажется у Вас методы самого тредпула из разных потоков нигде не вызываются.
ThreadPool/ThreadPool/IMyTask.cs
Outdated
| using System; | ||
|
|
||
| namespace ThreadPool | ||
| { |
There was a problem hiding this comment.
| using System; | |
| namespace ThreadPool | |
| { | |
| namespace ThreadPool; | |
| using System; |
И дальше без лишнего отступа, здесь и ниже. C# 10 же.
| if (_token.IsCancellationRequested) | ||
| { | ||
| throw new InvalidOperationException(); | ||
| } |
There was a problem hiding this comment.
Тут тоже можно было вызвать ReadyToAddNewTask()
| { | ||
| _waiterNewTask.Set(); | ||
| _waiterTaskDone.WaitOne(); | ||
| _waiterTaskDone.Reset(); |
There was a problem hiding this comment.
WaitOne же и так его опустит, это AutoResetEvent. По идее, этот Reset ничего не делает.
| private readonly ConcurrentQueue<Action> _tasksQueue = new(); | ||
| private readonly AutoResetEvent _waiterNewTask = new AutoResetEvent(false); | ||
| private readonly AutoResetEvent _waiterTaskDone = new AutoResetEvent(false); | ||
| private int _freeThreadsCount = 0; |
There was a problem hiding this comment.
Это должно быть volatile, потому что используется в Shutdown и рабочих потоках несинхронизированно. Есть риск дедлока в Shutdown, когда мы прочитали старое значение и пошли внутрь цикла, когда все потоки уже остановлены. Или в Shutdown Volatile.Read делать.
| /// </summary> | ||
| public MyTask(Func<TResult> function, MyThreadPool myThreadPool) | ||
| { | ||
| _func = function ?? throw new ArgumentNullException(nameof(function)); |
There was a problem hiding this comment.
Есть удобный метод ArgumentNullException.ThrowIfNull
| Assert.AreEqual(16, task2.Result); | ||
| Assert.AreEqual(28, task3.Result); | ||
| } | ||
| } |
There was a problem hiding this comment.
Всё ещё нужно. Кажется у Вас методы самого тредпула из разных потоков нигде не вызываются.
yurii-litvinov
left a comment
There was a problem hiding this comment.
Комментарии к коммитам ужасны. В остальном всё ок, зачтена.
No description provided.