Еще один вопрос блокировки - PullRequest
       12

Еще один вопрос блокировки

1 голос
/ 01 октября 2008

Я пытаюсь заблокировать понимание многопоточности. Я делаю все возможное, чтобы учить себя, но некоторые из этих вопросов нуждаются в разъяснении.

Я прошел три итерации с куском кода и экспериментировал с блокировкой.

В этом коде единственное, что требует блокировки, это this.managerThreadPriority.

Во-первых, простой процедурный подход с минималистической блокировкой.

var managerThread = new Thread
(
    new ThreadStart(this.ManagerThreadEntryPoint)
);

lock (this.locker)
{
    managerThread.Priority = this.managerThreadPriority;
}

managerThread.Name = string.Format("Manager Thread ({0})", managerThread.GetHashCode());

managerThread.Start();

Далее, один оператор для создания и запуска нового потока, но область блокировки кажется слишком большой, чтобы включать создание и запуск потока. Компилятор каким-то волшебным образом не знает, что блокировка может быть снята после использования this.managerThreadPriority.

Такого наивного блокирования следует избегать, я бы предположил.

lock (this.locker)
{
    new Thread
    (
        new ThreadStart(this.ManagerThreadEntryPoint)
    )
    {
        Priority = this.managerThreadPriority,
        Name = string.Format("Manager Thread ({0})", GetHashCode())
    }
    .Start();
}

И, наконец, один оператор для создания и запуска нового потока со встроенной блокировкой только вокруг общего поля.

new Thread
(
    new ThreadStart(this.ManagerThreadEntryPoint)
)
{
    Priority = new Func<ThreadPriorty>(() =>
    {
        lock (this.locker)
        {
            return this.managerThreadPriority;
        }
    })(),

    Name = string.Format("Manager Thread ({0})", GetHashCode())
}
.Start();

Не хотите прокомментировать информацию о пределах блокировки? Например, если мне нужно использовать поле в операторе if и это поле необходимо заблокировать, следует ли мне избегать блокировки всего оператора if? Э.Г.

bool isDumb;

lock (this.locker) isDumb = this.FieldAccessibleByMultipleThreads;

if (isDumb) ...

Vs.

lock (this.locker)
{
    if (this.FieldAccessibleByMultipleThreads) ...
}

Ответы [ 3 ]

3 голосов
/ 01 октября 2008

Не хотите прокомментировать информацию о пределах блокировки? Например, если я необходимо использовать поле в операторе if, и это поле должно быть заблокировано, мне следует избегать блокировки всего оператора if?

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

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

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

Иными словами, защищаете ли вы синхронный или асинхронный доступ к ресурсу ?

В целом синхронный доступ должен дольше удерживаться, поскольку он заботится о более широкой картине, частью которой является ресурс. Он должен поддерживать согласованность с соответствующими ресурсами. Вы можете очень хорошо обернуть весь цикл for в таком случае, если хотите предотвратить прерывания, пока все не будут обработаны.

Асинхронный доступ должен удерживаться на нем как можно более кратко. Таким образом, более подходящим местом для блокировки будут внутренние части кода, например, внутри цикла for или оператора if, чтобы вы могли сразу освободить отдельные элементы даже до обработки других элементов.


Помимо этих двух соображений, я бы добавил еще один. Избегать вложения замков, связанных с двумя различными объектами блокировки . Из опыта я узнал, что это вероятный источник взаимоблокировок, особенно если их используют другие части кода. Если два объекта являются частью группы, которую необходимо постоянно обрабатывать как одно целое, такая вложенность должна быть реорганизована.

3 голосов
/ 01 октября 2008

1) Прежде чем вы даже запустите другой поток, вам не нужно беспокоиться о совместном доступе к нему.

2) Да, вам следует заблокировать все доступ к общим изменяемым данным. (Если он неизменный, блокировка не требуется.)

3) Не используйте GetHashCode () для указания идентификатора потока. Используйте Thread.ManagedThreadId. Я знаю, есть книги, которые рекомендуют Thread.GetHashCode (), но посмотрите на документы.

0 голосов
/ 01 октября 2008

Нет необходимости блокировать что-либо до того, как вы запустите какие-либо темы.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...