Предоставление одновременного доступа для чтения и записи к объектам через WCF - PullRequest
1 голос
/ 11 октября 2010

У меня есть служба .NET 4 WCF, которая поддерживает поточно-ориентированный кэш-память объектов в памяти (SynchronizedObject).Я хочу обеспечить безопасный параллельный доступ для чтения и изменения как коллекции, так и объектов в коллекции.Безопасное изменение объектов и кэша может быть выполнено с помощью блокировок чтения-записи.

У меня проблемы с предоставлением доступа для чтения к объекту в кэше.Мой метод Read возвращает SynchronizedObject, но я не знаю, как элегантно убедиться, что никакие другие потоки не модифицируют объект, пока WCF сериализует SynchronizedObject.

Я попытался поместить предложение Read return внутри блокировки чтения иустановка точки останова в пользовательском XmlObjectSerializer.Когда вызывается метод XmlObjectSerializer :: WriteObject (Stream, object), блокировка чтения не удерживается в SynchronizedObject.

Меня особенно касается следующий сценарий:

  1. Поток A вызывает чтение (int).Выполнение продолжается только после оператора return.К этому моменту, наконец, также был выполнен, и блокировка чтения на SynchronizedObject была снята.Выполнение потока A. прерывается.
  2. Поток B вызывает Modify (int) для того же идентификатора.Блокировка записи доступна и получена.В какой-то момент между получением блокировки записи и ее снятием поток B прерывается.
  3. Поток A перезапускается и сериализация продолжается.Поток B имеет блокировку записи для того же SynchronizedObject и находится в середине некоторого критического раздела, но Поток A читает состояние SynchronizedObject и, таким образом, возвращает потенциально недопустимый объект вызывающей стороне Read (int).

Я вижу два варианта:

  • Поддерживать пользовательский XmlObjectSerializer, который захватывает блокировку чтения перед вызовом метода base.WriteObject (Stream, object) и освобождает его после.Мне не нравится эта опция, потому что подклассификация и переопределение функции сериализации каркаса для выполнения определенного действия, если объект для сериализации соответствует определенному типу, пахнет для меня.
  • Создание глубокой копии SynchronizedObjectв методе Read, пока удерживается блокировка чтения, снимите блокировку и верните глубокую копию.Мне не нравится эта опция, потому что будет много подклассов SynchronizedObject, для которых мне потребуется реализовать и поддерживать правильные глубокие копиры, а глубокие копии могут быть дорогими.

Какие другие опции делаютЯ имею?Как мне реализовать потокобезопасный метод чтения?

Я предоставил фиктивную службу ниже для более явных ссылок:


    public class Service : IService
    {
        IDictionary<int, SynchronizedObject> collection = new Dictionary<int, SynchronizedObject>();
        ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();

        public SynchronizedObject Read(int id)
        {
            rwLock.EnterReadLock();
            try
            {
                SynchronizedObject result = collection[id];
                result.rwLock.EnterReadLock();
                try
                {
                    return result;
                }
                finally
                {
                    result.rwLock.ExitReadLock();
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public void ModifyObject(int id)
        {
            rwLock.EnterReadLock();
            try
            {
                SynchronizedObject obj = collection[id];
                obj.rwLock.EnterWriteLock();
                try
                {
                    // modify obj
                }
                finally
                {
                    obj.rwLock.ExitWriteLock();
                }
            }
            finally
            {
                rwLock.ExitReadLock();
            }
        }

        public void ModifyCollection(int id)
        {
            rwLock.EnterWriteLock();
            try
            {
                // modify collection
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }
    }

    public class SynchronizedObject
    {
        public ReaderWriterLockSlim rwLock { get; private set; }

        public SynchronizedObject()
        {
            rwLock = new ReaderWriterLockSlim();
        }
    }

1 Ответ

1 голос
/ 11 октября 2010

Новый ответ

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

Предыдущий (не ценный) ответ

С http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.enterwritelock.aspx:

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

Итак, все, что вам нужно сделать, это вызвать EnterWriteLock и ExitWriteLock внутри ModifyObject (). Ваша попытка убедиться, что у вас есть как чтение, так и блокировка записи, фактически останавливает работу кода.

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