«используя» заявление против «попробуй наконец» - PullRequest
68 голосов
/ 10 ноября 2008

У меня есть куча свойств, для которых я собираюсь использовать блокировки чтения / записи. Я могу реализовать их с помощью try finally или using предложения.

В try finally я получу блокировку до try и отпущу в finally. В предложении using я бы создал класс, который получает блокировку в своем конструкторе и освобождает его в методе Dispose.

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

Метод 1 (try finally):

static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
    get
    {
        rwlMyLock_m .AcquireReaderLock(0);
        try
        {
            return dtMyDateTime_m
        }
        finally
        {
            rwlMyLock_m .ReleaseReaderLock();
        }
    }
    set
    {
        rwlMyLock_m .AcquireWriterLock(0);
        try
        {
            dtMyDateTime_m = value;
        }
        finally
        {
            rwlMyLock_m .ReleaseWriterLock();
        }
    }
}

Метод 2:

static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
    get
    {
        using (new ReadLock(rwlMyLock_m))
        {
            return dtMyDateTime_m;
        }
    }
    set
    {
        using (new WriteLock(rwlMyLock_m))
        {
            dtMyDateTime_m = value;
        }
    }
}

public class ReadLock : IDisposable
{
    private ReaderWriterLock rwl;
    public ReadLock(ReaderWriterLock rwl)
    {
        this.rwl = rwl;
        rwl.AcquireReaderLock(0);
    }

    public void Dispose()
    {
        rwl.ReleaseReaderLock();
    }
}

public class WriteLock : IDisposable
{
    private ReaderWriterLock rwl;
    public WriteLock(ReaderWriterLock rwl)
    {
        this.rwl = rwl;
        rwl.AcquireWriterLock(0);
    }

    public void Dispose()
    {
        rwl.ReleaseWriterLock();
    }
}

Ответы [ 15 ]

0 голосов
/ 31 мая 2009

SoftwareJedi, у меня нет учетной записи, поэтому я не могу редактировать свои ответы.

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

class StackOTest
{
    static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
    private DateTime dtMyDateTime_m;
    public DateTime MyDateTime
    {
        get
        {
            DateTime retval = default(DateTime);
            ReadLockedMethod(
                delegate () { retval = dtMyDateTime_m; }
            );
            return retval;
        }
        set
        {
            WriteLockedMethod(
                delegate () { dtMyDateTime_m = value; }
            );
        }
    }

    private void ReadLockedMethod(Action method)
    {
        rwlMyLock_m.AcquireReaderLock(0);
        try
        {
            method();
        }
        finally
        {
            rwlMyLock_m.ReleaseReaderLock();
        }
    }

    private void WriteLockedMethod(Action method)
    {
        rwlMyLock_m.AcquireWriterLock(0);
        try
        {
            method();
        }
        finally
        {
            rwlMyLock_m.ReleaseWriterLock();
        }
    }
}
0 голосов
/ 31 мая 2009

Глупый я. Есть способ сделать это еще проще, сделав заблокированные методы частью каждого экземпляра (вместо статического, как в моем предыдущем посте). Теперь я действительно предпочитаю это, потому что нет необходимости передавать `rwlMyLock_m 'другому классу или методу.

class StackOTest
{
    private delegate DateTime ReadLockMethod();
    private delegate void WriteLockMethod();

    static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
    private DateTime dtMyDateTime_m;
    public DateTime MyDateTime
    {
        get
        {
            return ReadLockedMethod(
                delegate () { return dtMyDateTime_m; }
            );
        }
        set
        {
            WriteLockedMethod(
                delegate () { dtMyDateTime_m = value; }
            );
        }
    }

    private DateTime ReadLockedMethod(ReadLockMethod method)
    {
        rwlMyLock_m.AcquireReaderLock(0);
        try
        {
            return method();
        }
        finally
        {
            rwlMyLock_m.ReleaseReaderLock();
        }
    }

    private void WriteLockedMethod(WriteLockMethod method)
    {
        rwlMyLock_m.AcquireWriterLock(0);
        try
        {
            method();
        }
        finally
        {
            rwlMyLock_m.ReleaseWriterLock();
        }
    }
}
0 голосов
/ 31 мая 2009

Я удивлен, что никто не предложил инкапсулировать try-finally в анонимные функции. Так же, как и метод создания и удаления классов с помощью оператора using, это удерживает блокировку в одном месте. Я сам предпочитаю это только потому, что предпочитаю читать слово «наконец», чем слово «Утилизировать», когда я думаю о снятии блокировки.

class StackOTest
{
    private delegate DateTime ReadLockMethod();
    private delegate void WriteLockMethod();

    static ReaderWriterLock rwlMyLock_m  = new ReaderWriterLock();
    private DateTime dtMyDateTime_m;
    public DateTime MyDateTime
    {
        get
        {
            return ReadLockedMethod(
                rwlMyLock_m,
                delegate () { return dtMyDateTime_m; }
            );
        }
        set
        {
            WriteLockedMethod(
                rwlMyLock_m,
                delegate () { dtMyDateTime_m = value; }
            );
        }
    }

    private static DateTime ReadLockedMethod(
        ReaderWriterLock rwl,
        ReadLockMethod method
    )
    {
        rwl.AcquireReaderLock(0);
        try
        {
            return method();
        }
        finally
        {
            rwl.ReleaseReaderLock();
        }
    }

    private static void WriteLockedMethod(
        ReaderWriterLock rwl,
        WriteLockMethod method
    )
    {
        rwl.AcquireWriterLock(0);
        try
        {
            method();
        }
        finally
        {
            rwl.ReleaseWriterLock();
        }
    }
}
0 голосов
/ 11 ноября 2008

Хотя я согласен со многими из вышеприведенных комментариев, включая детализацию блокировки и сомнительную обработку исключений, этот вопрос является одним из подходов. Позвольте мне привести одну серьезную причину, по которой я предпочитаю использовать абстракцию try {} finally ...

У меня есть модель, очень похожая на вашу, за одним исключением. Я определил базовый интерфейс ILock и в нем я предоставил один метод с именем Acquire (). Метод Acquire () возвратил объект IDisposable, и в результате это означает, что пока объект, с которым я имею дело, имеет тип ILock, его можно использовать для создания области блокировки. Почему это важно?

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

interface ILock {
    IDisposable Acquire();
}

class MonitorLock : ILock {
    IDisposable Acquire() { ... acquire the lock for real ... }
}

Мне нравится ваша модель, но я бы подумал спрятать механизм блокировки от звонящего. FWIW, я измерил издержки использования метода по сравнению с try-finally, и накладные расходы на выделение одноразового объекта будут иметь 2-3% накладных расходов производительности.

0 голосов
/ 10 ноября 2008

Я думаю, что метод 2 будет лучше.

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