Должен ли оператор return быть внутри или снаружи блокировки?

131
задан yoozer8 3 January 2013 в 20:17
поделиться

7 ответов

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

Для показа различия в IL, позволяет коду:

static class Program
{
    static void Main() { }

    static readonly object sync = new object();

    static int GetValue() { return 5; }

    static int ReturnInside()
    {
        lock (sync)
        {
            return GetValue();
        }
    }

    static int ReturnOutside()
    {
        int val;
        lock (sync)
        {
            val = GetValue();
        }
        return val;
    }
}

(обратите внимание, что я счастливо обсудил бы это ReturnInside более простой/более чистый бит C#),

И посмотрите на IL (режим выпуска и т.д.):

.method private hidebysig static int32 ReturnInside() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 CS$1$0000,
        [1] object CS$2$0001)
    L_0000: ldsfld object Program::sync
    L_0005: dup 
    L_0006: stloc.1 
    L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object)
    L_000c: call int32 Program::GetValue()
    L_0011: stloc.0 
    L_0012: leave.s L_001b
    L_0014: ldloc.1 
    L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object)
    L_001a: endfinally 
    L_001b: ldloc.0 
    L_001c: ret 
    .try L_000c to L_0014 finally handler L_0014 to L_001b
} 

method private hidebysig static int32 ReturnOutside() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 val,
        [1] object CS$2$0000)
    L_0000: ldsfld object Program::sync
    L_0005: dup 
    L_0006: stloc.1 
    L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object)
    L_000c: call int32 Program::GetValue()
    L_0011: stloc.0 
    L_0012: leave.s L_001b
    L_0014: ldloc.1 
    L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object)
    L_001a: endfinally 
    L_001b: ldloc.0 
    L_001c: ret 
    .try L_000c to L_0014 finally handler L_0014 to L_001b
}

Таким образом на уровне IL они - [плюс-минус некоторые имена] идентичный (я изучил что-то;-p). По сути, единственное разумное сравнение является (очень субъективным) законом локального стиля кодирования... Я предпочитаю ReturnInside для простоты, но я не пришел бы в восторг от также.

179
ответ дан Marc Gravell 3 January 2013 в 20:17
поделиться

Это не имеет никакого значения; они оба переводятся в то же самое компилятором.

Для разъяснения любой эффективно переводится во что-то со следующей семантикой:

T myData;
Monitor.Enter(mutex)
try
{
    myData= // something
}
finally
{
    Monitor.Exit(mutex);
}

return myData;
37
ответ дан Greg Beech 3 January 2013 в 20:17
поделиться

Это зависит,

я собираюсь идти вразрез с мелкой частицей здесь. Я обычно возвращался бы в блокировке.

Обычно переменная mydata является локальной переменной. Я люблю объявление локальных переменных, в то время как я инициализирую их. У меня редко есть данные для инициализации моего возвращаемого значения за пределами моей блокировки.

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

void example() { 
    int myData;
    lock (foo) { 
        myData = ...;
    }
    return myData
}

по сравнению с

void example() { 
    lock (foo) {
        return ...;
    }
}

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

4
ответ дан Edward KMETT 3 January 2013 в 20:17
поделиться

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

return f(...)

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

5
ответ дан Rob Walker 3 January 2013 в 20:17
поделиться

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

31
ответ дан Sjon 3 January 2013 в 20:17
поделиться

Вне смотрит инструмент для очистки.

0
ответ дан Ovidiu Pacurar 3 January 2013 в 20:17
поделиться

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

1
ответ дан Adam Asham 3 January 2013 в 20:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: