Упрощение синтаксиса ReaderWriterLockSlim - PullRequest
2 голосов
/ 20 июля 2011

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

class Locked<T>
{
    private T _resource;
    private ReaderWriterLockSlim _lock;

    public Locked(T resource)
    {
        _resource = resource;
        _lock = new ReaderWriterLockSlim();
    }

    public void Read(Action<T> ReadAction)
    {
        try
        {
            _lock.EnterReadLock();
            ReadAction(_resource);
        }
        finally
        {
            _lock.ExitReadLock();
        }
    }

    public void Write(Action<T> WriteAction)
    {
        try
        {
            _lock.EnterWriteLock();
            WriteAction(_resource);
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
}

Теперь, например, если нам нужно синхронизировать доступ к List<string>, то, как мы это делаем, используя класс выше

public class Demo
{
    private Locked<List<string>> _listOfString;

    public Demo()
    {
        _listOfString = new Locked<List<string>>(new List<string>());
    }

    public void writeMethod(string value)
    {
        _listOfString.Write(list =>
        {
            list.Add(value);
        });
    }

    public string readMethod(int index)
    {
        string value = null;
        _listOfString.Read(list =>
        {
            value = list[index];
        });
        return value;
    }
}

Как вы думаете, этот подход лучше? Есть ли недостатки или недостатки.

1 Ответ

4 голосов
/ 20 июля 2011

Я бы предпочел заключить логику блокировки в IDisposable и поместить код, который вы хотите заблокировать, в блок using, очень похожий на оператор lock:

class DisposableLock : IDisposable
{
    Action _exitLock;
    public DisposableLock(Action exitLock)
    {
        _exitLock = exitLock;
    }

    public void Dispose()
    {
        _exitLock();
    }
}

class ReadLock : DisposableLock
{
    public ReadLock(ReaderWriterLockSlim slimLock)
        : base(() => slimLock.ExitReadLock())
    {
        slimLock.EnterReadLock();
    }
}

class WriteLock : DisposableLock
{
    public WriteLock(ReaderWriterLockSlim slimLock)
        : base(() => slimLock.ExitWriteLock())
    {
        slimLock.EnterWriteLock();
    }
}

Вы бы использовали это так:

using(new ReadLock(_lock))
{
    // ... your synchronized operation
}

using(new WriteLock(_lock))
{
    // ... your synchronized operation
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...