-
Notifications
You must be signed in to change notification settings - Fork 0
Thread pool #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Thread pool #3
Conversation
ThreadPool/ThreadPool/IMyTask.cs
Outdated
| namespace ThreadPool | ||
| { | ||
| /// <summary> | ||
| /// task interface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Понятно что это интерфейс, но что это за интерфейс?
ThreadPool/ThreadPool/MyTask.cs
Outdated
| namespace ThreadPool | ||
| { | ||
| /// <summary> | ||
| /// task classs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тоже не очень, даже более не очень, чем в предыдущем случае :)
ThreadPool/ThreadPool/MyTask.cs
Outdated
| /// <summary> | ||
| /// task classs | ||
| /// </summary> | ||
| public class MyTask<TResult> : IMyTask<TResult> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Его лучше сделать 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Можно более специфично, ArgumentNullException(nameof(function));
ThreadPool/ThreadPool/MyTask.cs
Outdated
| _resultException = funcException; | ||
| } | ||
|
|
||
| lock (_locker) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это, как я понимаю, задел на будущее, потому что пока синхронизироваться не с кем
| { | ||
| if (countThreads < 1) | ||
| { | ||
| throw new ArgumentException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArgumentOutOfRangeException(nameof(countThreads));
| } | ||
|
|
||
| var task = new MyTask<TResult>(function); | ||
| _tasksQueue.Enqueue(task.Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Не-а, если в этот момент сделают 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это не нужно, собирайте библиотеку просто
| _threadPool.AddTask(() => | ||
| { | ||
| Interlocked.Increment(ref number); | ||
| Thread.Sleep(3000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Для этого есть всякие ManualResetEvent-ы, а то очень долго тесты исполняться будут
| } | ||
| } | ||
|
|
||
| var task = new MyTask<TResult>(function, this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Мм, и в этот момент происходит Shutdown, все потоки останавливаются, но мы уже не можем отменить добавление таска.
| while (_continueWithTasksQueue.Count > 0) | ||
| { | ||
| var action = _continueWithTasksQueue.Dequeue(); | ||
| lock (_locker) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Двойной lock на _locker? Если бы lock в C# был не рекурсивным, был бы дедлок :) Может, имелся в виду lockObject из тредпула? Но тогда доверили бы тредпулу им управлять
| lock (_locker) | ||
| { | ||
| _myThreadPool._tasksQueue.Enqueue(action); | ||
| _waiterManual.Set(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Он и так выставлен тут уже. Или, опять-таки, имелся в виду флаг из тредпула?
|
|
||
| var task = new MyTask<TNewResult>(() => func(Result), _myThreadPool); | ||
| _continueWithTasksQueue.Enqueue(task.Count); | ||
| if (IsCompleted) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Если IsCompleted, можно просто добавлять таск на тредпул, даже лочить никого не надо. О задачах из очереди позаботится Count. А то тут как-то очень много всего в критической секции.
yurii-litvinov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Надо ещё немного поправить
|
|
||
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это лучше доверить самому тредпулу. И это не синхронизировано с Shutdown, так что хоть, кажется, и будет работать (потому что у Вас потоки останавливаются только когда очередь пуста, а тут она гарантированно не пуста, потому что какой-то поток нас сейчас как раз и считает на 39-й строчке, и мы ему ещё задач накидаем), но это ни разу не очевидно и стоило хотя бы в комментарии написать.
| { | ||
| throw new InvalidOperationException(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Лучше сделайт требпулу приватный метод "Готов принимать новые задачи" и вызывайте его тут и в 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Надо бы ещё тесты на параллельные запросы к тредпулу (например, Shutdown и AddTask, что ничего не дедлочится)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Всё ещё нужно. Кажется у Вас методы самого тредпула из разных потоков нигде не вызываются.
ThreadPool/ThreadPool/IMyTask.cs
Outdated
| using System; | ||
|
|
||
| namespace ThreadPool | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| using System; | |
| namespace ThreadPool | |
| { | |
| namespace ThreadPool; | |
| using System; |
И дальше без лишнего отступа, здесь и ниже. C# 10 же.
| if (_token.IsCancellationRequested) | ||
| { | ||
| throw new InvalidOperationException(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут тоже можно было вызвать ReadyToAddNewTask()
| { | ||
| _waiterNewTask.Set(); | ||
| _waiterTaskDone.WaitOne(); | ||
| _waiterTaskDone.Reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это должно быть 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Есть удобный метод ArgumentNullException.ThrowIfNull
| Assert.AreEqual(16, task2.Result); | ||
| Assert.AreEqual(28, task3.Result); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Всё ещё нужно. Кажется у Вас методы самого тредпула из разных потоков нигде не вызываются.
yurii-litvinov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Комментарии к коммитам ужасны. В остальном всё ок, зачтена.
No description provided.