Задания работают одним методом. Как предотвратить дублирование кода?

Предположим, есть две задачи:

Task.Run(() => {
    while (!this.isCanceled)
        DoOperation(obj);
});

а также

Task.Run(() => {
    foreach(var obj in objects)   // Another objects' subset
        while(!this.isCancelled)
            DoOperation(obj);
});

И DoOperation(Foo obj) реализация:

DoOperation(Foo obj)
{
    if (obj.IsBar && obj.IsFoo)
        obj.MakeSad();
    else
        obj.MakeHappy();
}

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

Итак, вопрос в том, как избежать блокировки и предотвратить дублирование кода?


person Aleksandr Necheukhin    schedule 26.12.2019    source источник


Ответы (1)


Каков критический код, если ваша операция? Должны быть одно или несколько условий гонки, или вообще не нужно использовать блокировки.

Если в вашем примере это что-то в DoSomething, то используйте блокировку там:

DoOperation(Foo obj)
{
    if (obj.IsBar && obj.IsFoo)
        obj.MakeSad();
    else {
        lock(lockObject1) {
             obj.MakeHappy();
        }
    }
}

Таким образом, вы не дублируете код и все остальное, если функции работают без блокировки. Если используется другой оспариваемый блок, используйте другой объект блокировки, чтобы они не блокировали друг друга.

Кстати, поскольку вы используете задачи и программирование синхронизации, лучше использовать пользователя SemaphoreSlim для блокировки https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/amp/

person Athanasios Kataras    schedule 26.12.2019
comment
В методе DoSomething проблем нет, потому что он работает с разными объектами Foo, но я думаю, что этот метод все еще может иметь некоторые проблемы с вызовами разных объектов с разными задачами. Возможно ли, например, иметь вызов obj.MakeHappy(), где адрес объекта в стек - это что-то вроде 0x04a1 по другой ссылке (адрес объекта 0x9a2c), связанный с несколькими задачами? - person Aleksandr Necheukhin; 26.12.2019