Skip to content

My thread pool#22

Open
Palezehvat wants to merge 17 commits intomasterfrom
MyThreadPool
Open

My thread pool#22
Palezehvat wants to merge 17 commits intomasterfrom
MyThreadPool

Conversation

@Palezehvat
Copy link
Owner

No description provided.

/// <summary>
/// A method for solving subtasks from the results obtained from the tasks
/// </summary>
public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler);

Choose a reason for hiding this comment

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

Комментарии должны присутствовать у всех public-методов, а не выборочно :)

/// <summary>
/// A method for solving subtasks from the results obtained from the tasks
/// </summary>
public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler);

Choose a reason for hiding this comment

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

supplier
Здесь и в других местах

private readonly CancellationTokenSource token = new();
private readonly Object lockerForThreads;
private readonly Object lockerForTasks;
private volatile bool stopCount = false;

Choose a reason for hiding this comment

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

Компилятор ругается, что значение поля нигде не используется

/// 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)
{

Choose a reason for hiding this comment

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

Здесь надо учесть условие "после вызова Shutdown новые задачи не принимаются на исполнение потоками из пула", а также согласовать исполнение метод с Shutdown (сделать так, чтобы не было гонок при вызове Submit и Shutdown одновременно из разных потоков)

Choose a reason for hiding this comment

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

Согласование Submit с Shutdown -- не готово.
(для этого надо использовать lock по защищаемому ресурсу)

Comment on lines 58 to 61
if (token.IsCancellationRequested)
{
;
}

Choose a reason for hiding this comment

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

Это как?..

Choose a reason for hiding this comment

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

Видимо, поле stopCount создавалось как показатель, был ли уже запрошен Shutdown. Тогда надо его либо свойством сделать, либо вообще убрать. Если свойством сделать, то у stopCount будет хоть какое-то гипотетическое применение в виде запрашивания извне.
И назвать тогда как-то понятнее, типо IsShutdownRequested

isCompleted = true;
while (queueWithContinueWithTasks.Count > 0)
{
queueWithTasks.Enqueue(queueWithContinueWithTasks.Dequeue());

Choose a reason for hiding this comment

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

По-хорошему, напрямую с очередью должен работать только пул и его треды. Task - это уже другой уровень абстракции, он лишь вызывает методы треда типо Submit. Поэтому здесь надо переписать через Submit треда

private volatile bool isCompleted = false;
private TResult? result;
private readonly Queue<Action> queueWithContinueWithTasks;
private readonly MyThread[] arrayThreads;

Choose a reason for hiding this comment

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

Зачем это поле?

}

public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler)
{

Choose a reason for hiding this comment

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

Здесь тоже прямую работу с очередью задач пула надо заменить на Submit. Иначе если кто-угодно будет его очередь менять, сложно будет найти ошибку. Да и не в духе ООП это

}

public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> suppiler)
{

Choose a reason for hiding this comment

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

Здесь тоже надо позаботиться об отсутствии гонок между ContinueWith и Shutdown, между добавлением continuation-ов на пул и Shutdown (используя lock(и))

Assert.That(Equals(myTask.Result, "16"));
myThreadPool.Shutdown();
}
} No newline at end of file
Copy link

@YuriUfimtsev YuriUfimtsev Nov 4, 2023

Choose a reason for hiding this comment

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

Тестов стоит добавить: тест, проверяющий, что в пуле действительно не менее n потоков; тест на корректность IsCompleted, Result (в случае с исключением); тест на Shutdown (проверить, что "уже запущенные задачи не прерываются, но новые задачи не принимаются на исполнение потоками из пула"); тесты на конкурентный доступ к методам пула из нескольких потоков (submit задач из разных потоков, Submit и Shutdown одновременно)

Copy link

@YuriUfimtsev YuriUfimtsev left a comment

Choose a reason for hiding this comment

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

Уже лучше, но исправлено не всё. И куда-то исчез механизм работы с continuation-ами задач

Comment on lines 135 to 138
if (token.IsCancellationRequested)
{
return;
}

Choose a reason for hiding this comment

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

Это зачем? Само выйдет

/// 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)
{

Choose a reason for hiding this comment

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

Согласование Submit с Shutdown -- не готово.
(для этого надо использовать lock по защищаемому ресурсу)


if (!token.IsCancellationRequested)
{
return pool.Submit(() => supplier(Result));

Choose a reason for hiding this comment

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

Ниже компилятор ругается: действительно, почему supplier может быть null?

waitHandle.WaitOne();
if (!token.IsCancellationRequested)
{
lock (locker)

Choose a reason for hiding this comment

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

Здесь lock по очереди задач надо, как ранее писал

/// <summary>
/// A method for solving subtasks from the results obtained from the tasks
/// </summary>
public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> supplier)

Choose a reason for hiding this comment

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

Здесь и в StartSupplier куда-то пропала функциональность по добавлению всех continuation-ов в очередь и сабмиту этих continuation-ов в тредпул, когда "базовая" задача досчиталась. А это для выполнения условий задачи важно

Comment on lines +33 to +34
Assert.That(firstTask.Result, Is.EqualTo(4));
Assert.That(secondTask.Result, Is.EqualTo(6));

Choose a reason for hiding this comment

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

А вот это хорошо, никаких Assert.That(Equals(..)) 👍

private TResult? result;
private Exception? exception;
private CancellationTokenSource token;
private EventWaitHandle waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

Choose a reason for hiding this comment

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

Эквивалентно

Suggested change
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);

Choose a reason for hiding this comment

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

Здесь тоже лучше ManualResetEvent использовать. Хотя если вы его используйте для пропуска одного потока для выполнения задачи при Submit, то лучше AutoResetEvent. MRE только все потоки умеет пропускать за раз


[Test]
public void NumberThreadsTheRequiredNumberIsCreated()
{
Copy link

@YuriUfimtsev YuriUfimtsev Dec 21, 2023

Choose a reason for hiding this comment

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

Не, так просто не получится. Вдруг GetNumberOfThreads просто заданное число возвращает :)
Здесь надо загрузить все потоки пула задачами и проверить, что новая добавленная задача не будет принята на исполнение. Для того, чтобы загрузить потоки задачами, внутри задач можно использовать ManualResetEvent


using MyThreadPool;

public class Tests

Choose a reason for hiding this comment

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

Тестов на конкурентный доступ к методам пула по-прежнему не хватает

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

Comments