Skip to content

Thread pool#51

Open
IgnatSergeev wants to merge 13 commits intomainfrom
thread-pool
Open

Thread pool#51
IgnatSergeev wants to merge 13 commits intomainfrom
thread-pool

Conversation

@IgnatSergeev
Copy link
Owner

No description provided.

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.

Если метод возвращает значение, то это не просто так. Здесь стоит его получить и в if учесть

Choose a reason for hiding this comment

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

Надо в цикл добавить использование ResetEvent-а\ов, чтобы не было крутящейся блокировки, и потоки при отсутствии задач на WaitOne стояли. Потому что в случае с WaitOne происходит системный вызов, и пока Set не установят, управление этому потоку не перейдет в отличие от обычного цикла, который будет бесконечно крутиться и съедать ресурсы

Choose a reason for hiding this comment

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

Интересное решение. И по корректности работы не уступает CancellationTokenSource.
Однако в скорости проигрывает из-за volatile, и учитывая, что эти проверки будут постоянно проводиться в циклах потоков и не только, лучше классический вариант использовать с CancellationTokenSource

/// <typeparam name="TResult">Func return type</typeparam>
/// <returns>I my task instance of one added to pool</returns>
public IMyTask<TResult> Submit<TResult>(Func<TResult> func)
{

Choose a reason for hiding this comment

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

Здесь не хватает проверки _isTerminated, из-за чего можем одним из потоков добавить задачу после вызова Shutdown, противоречие с условием.
Более того, надо лочиться по очереди задач пула здесь и в Shutdown, чтобы между ними гонок не возникало

Choose a reason for hiding this comment

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

Закладывается ли в поведение объектов MyTask возможность по нескольку раз вызывать метод Execute? Как-будто бы нет, учитывая, что этот метод и в интерфейс не выносится.
Так что lock (и volatile-операции, кстати, несколько потоков же Execute тоже не вызывают) можно убрать, а то сейчас больше похоже на реализацию многопоточного lazy :)

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.

processes? processors? :)

Choose a reason for hiding this comment

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

Необычно, но где гарантия, что эти потоки именно в пуле, а не созданы где-то в стороне (например, в одном из тестов).
Чтобы проверить число потоков именно в пуле можно, например, создать n задач с waitOne, проверить, что все потоки заняты (выполняют задачу), добавить n+1, проверить, что очередь задач не пуста (это, конечно, потребует добавления пары свойств в класс пула)

System.Diagnostics.Process.GetCurrentProcess().Refresh();
Assert.That(System.Diagnostics.Process.GetCurrentProcess().Threads, Has.Count.EqualTo(_procAmount + 4));
}
} No newline at end of file

Choose a reason for hiding this comment

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

Не хватает тестов на конкурентный доступ к методам пула из нескольких потоков: submit задач из разных потоков, Submit и Shutdown одновременно, ContinueWith и Shutdown

Choose a reason for hiding this comment

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

Assert.That(secTask.IsCompleted, Is.True);
});

_pool!.Submit(TestFunc);

Choose a reason for hiding this comment

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

Это не должно быть возможно после Shutdown по условию

System.Diagnostics.Process.GetCurrentProcess().Refresh();
Assert.That(System.Diagnostics.Process.GetCurrentProcess().Threads, Has.Count.EqualTo(_procAmount + 4));
}
} No newline at end of file

Choose a reason for hiding this comment

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

@@ -0,0 +1,8 @@
namespace MyThreadPool;

public class MyThreadCreationException : Exception

Choose a reason for hiding this comment

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

Надо комментарии

var task = new MyTask<TResult>(func, this);
lock (this._cancellation)
{
if (!this._cancellation.IsCancellationRequested)

Choose a reason for hiding this comment

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

А если нет, нам возвращают задачу, которую никто не собирается делать. Обращаемся к её свойству Result — дедлок.

}

public TResult Result()
{

Choose a reason for hiding this comment

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

Э нет, так нельзя. Надо проектировать API не исходя из того, чья будет в чём вина, а чтобы его удобно было использовать. Потенциальный дедлок — это вообще ни разу не "удобно использовать".

this.IsCompleted = true;
this._completeEvent.Set();
}
lock(this._nextTasks)

Choose a reason for hiding this comment

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

Suggested change
lock(this._nextTasks)
lock (this._nextTasks)

public TResult Result =>
this._completeEvent.WaitOne() && this._threwException ? throw this._exception : this._result!;


Choose a reason for hiding this comment

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

Лишняя пустая строчка :)

Comment on lines +150 to +151
}
public IMyTask<TNewResult> ContinueWith<TNewResult>(Func<TResult, TNewResult> nextDelegate)

Choose a reason for hiding this comment

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

А тут наоборот пустой строчки не хватает

if (this.IsCompleted)
{
return this._threadPool.Submit(() => nextDelegate(this._result!));
Console.WriteLine("Added after Completed");

Choose a reason for hiding this comment

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

Тут даже CI говорит, что недостижимый код. Хоть он и, видимо, для отладки.

{
if (!this._threadPool._cancellation.IsCancellationRequested)
{
this._nextTasks.Add(nextTask.Execute);

Choose a reason for hiding this comment

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

Вроде как дедлок, из-за которого не проходят тесты, тут — мы continuation ставим на пул, но не говорим пулу, что ему свалилась новая задача, так что все рабочие потоки сидят и ждут пока семафор откроется. А тест ждёт Result у continuation-а. Иногда ему везёт и ContinueWith отрабатывает, когда задача уже посчиталась, тогда тест проходит.

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