Skip to content

3. MyThreadPool - #3

Open
ArtemNikit1n wants to merge 4 commits into
mainfrom
03-my-thread-pool
Open

3. MyThreadPool#3
ArtemNikit1n wants to merge 4 commits into
mainfrom
03-my-thread-pool

Conversation

@ArtemNikit1n

Copy link
Copy Markdown
Owner

No description provided.

@@ -0,0 +1,103 @@
// <copyright file="MyThreadPoolTests.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Надо зарегистрировать ООО "PlaceholderCompany" и жить на доходы от патентного троллинга.

public void Constructor_WithZeroThreads_Should_ThrowArgumentException()
{
Assert.Throws<ArgumentException>(() => { _ = new MyThreadPool(0); });
}

This comment was marked as resolved.

[Test]
public void Dispose_Should_CallShutdown()
{
var pool = new MyThreadPool(2);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы это в SetUp вынес, чтобы кучу раз не писать.


Assert.Throws<InvalidOperationException>(() => pool.Submit(() => 42));
}
}

This comment was marked as resolved.

public interface IMyTask<out TResult>
{
/// <summary>
/// Gets a value indicating whether it gets a value true if the task is completed. If the result is not yet ready, it returns false.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Gets a value indicating whether it gets a value true if the task is completed" — 🤔

{
ArgumentNullException.ThrowIfNull(newFunction);

return this.threadPool.Submit(ContinuationFunction);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так в пул будут ставиться ещё не готовые к работе задачи, которые заблочатся на Result "родительской" задачи. Так вполне может оказаться, что все потоки пула ждут, пока закончится одна задача, и ничего не делают, тогда как в очереди куча быстрых и готовых к запуску задач, которые просто некому делать. Так что ставить в пул продолжения надо только когда "родительская" задача закончена.


TNewResult ContinuationFunction()
{
var sourceResult = this.Result;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если родительская задача завершилась с исключением, тут беда будет.

if (threadCount <= 0)
{
throw new ArgumentException("Thread count must be positive.", nameof(threadCount));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Используйте ArgumentOutOfRangeException.ThrowIfLessOrEqual.

throw new InvalidOperationException("ThreadPool is shutting down.");
}

var task = new MyTask<TResult>(function, this);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прямо вот здесь this.isDisposed может уже быть true. taskQueue.Add бросит исключение, так что вроде как ничего не сломается, но но несинхронизированная проверка разделяемой между потоками переменной всегда вызывает ощущение лёгкого удивления.

return;
}

this.isDisposed = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут тоже, никто не мешает вызвать Shutdown из двух потоков одновременно.

@yurii-litvinov yurii-litvinov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Уже не актуально, но вроде как теперь почти всё правильно

{
try
{
var task = this.poolWithThreeThreads.Submit(() =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Стоило бы для пущей убедительности стартовать Submit по максимуму одновременно, добавив сюда ManualResetEvent.Wait, и выставлять его перед Assert-ом. А то тут не исключено, что все Submit-ы будут делаться строго последовательно и вообще в одном потоке — задача-то короткая, легко укладывается в один квант времени.

this.isCompleted = true;
this.completionEvent.Set();
this.StartContinuations();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ещё бы занулить function, чтобы сборщик мусора мог её собрать (со всем её замыканием, которое может включать в себя полсистемы).

public void Start()
{
_ = this.lazyTask.Value;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут тоже => была бы вполне ок.

=> this.lazyTask.Value.Result;

public IMyTask<TNextResult> ContinueWith<TNextResult>(Func<TNewResult, TNextResult> function)
=> this.lazyTask.Value.ContinueWith(function);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хм, так вызов ContinueWith у ещё не посчитавшейся задачи приведёт к её внезапной и несвоевременной постановке на тредпул, как я понял. Тут Lazy — некий оверкилл на самом деле, MyTask и так почти Lazy, можно было бы требуемую функциональность без таких странных побочных эффектов реализовать вручную (или обойтись обычным MyTask на самом деле). Правда, с Lazy не надо разбираться, в какой поток Submit выкинет исключение, это большой плюс такого подхода.

private readonly List<Thread> threads;
private readonly CancellationTokenSource cancellationTokenSource;
private volatile bool isDisposed;
private readonly Lock shutdownLock = new();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут стоило поправить предупреждения от StyleCop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants