2014-10-23 2 views
1

У нас есть несколько полных lock-s в нашем веб-приложении, которые могут быть более эффективными, если бы они были заменены на блокировки чтения-записи - даже с дополнительными накладными расходами блокировки RW, наш код был бы более параллельным. К сожалению, я не могу использовать ReaderWriterLockSlim из-за того, что кажется довольно большой ошибкой синхронизации, которая может привести к взаимоблокировкам на определенном оборудовании. This article подробно объясняет проблему.«Повторное выполнение» (клонирование) ReaderWriterLockSlim

Данная проблема исправлена ​​в .NET Framework 4.0.30319.33440, но не все версии сервера Windows получают это исправление. У исправления Windows 8.1 и Windows Server 2012 R2 есть исправление. Windows Server 2012 (не R2) и Windows Server 2008 R2 все еще имеют ошибку даже после последних исправлений. Похоже, Microsoft не планирует устранять эту проблему на всех платформах.

В наших различных серверных средах используются разные версии Windows Server, и я подтвердил, что некоторые серверы имеют исправление, а некоторые нет. Это означает, что я не могу безопасно изменить все эти операторы lock на блокировки считывателя-писателя, потому что на некоторых наших серверах приложение может блокироваться случайным образом.

В качестве альтернативы, я смотрю в реализовав ReaderWriterLockSlim по декомпиляции кода в System.Core и создания нового класса (что-то вроде MyRWLock), который имеет одну функцию (известный) багги ExitMyLock неподвижную. Весь другой код совпадает с оригиналом ReaderWriterLockSlim.

Для этого необходимо удалить все атрибуты __DynamicallyInvokable и добавить 2 или 3 класса/структуры, которые являются внутренними по отношению к System.Core. Я сделал все это, и новый класс блокировки компилируется без ошибок.

Мой вопрос: может кто-нибудь подумать о какой-либо причине, что этот новый класс не будет работать как оригинальный класс ReaderWriterLockSlim? Я считаю себя довольно хорошим, когда дело доходит до резьбы, но я не эксперт. Поскольку я не менял никакого кода (кроме исправления некоторых имен типов, чтобы указать на новый MyRWLock вместо ReaderWriterLockSlim и атрибуты), я считаю, что это должно сработать. Однако я действительно удивляюсь, если я забыл о чем-то, что может сломать это различными способами, которые трудно отлаживать.

В качестве альтернативы: является ли моя (и связанная статья) неправильной? Во-первых, эта проблема не нуждается в исправлении? Автор этой статьи, похоже, сделал очень подробный анализ, который выглядит правильно для меня, но Microsoft не применяла изменения к некоторым версиям Windows Server.

Любые мысли об этом будут высоко оценены.

Edit:

Чтобы добавить контекст для полных замков, вот что они нужны. У нас есть служба, которая читает/записывает удаленный сервис, когда выполняет свою работу. Есть много других чтений, чем пишет. Чтение включает в себя 1 круговое путешествие по сети, и запись включает в себя 3 сетевых перехода к удаленной службе. Когда происходит запись, чтение не может произойти (запись действительно является read-> delete-> add). Прямо сейчас, мы используем полные lock-ы вокруг всех этих операций, но это означает, что все потоки, которые пытаются читать, все еще должны стоять в очереди до тех пор, пока текущее чтение не закончится, даже без записи. Мне кажется, что замок RW идеально подходит для этого.

+0

', который мог бы быть более эффективным, если бы они были заменены на блокировки чтения-записи', Первый профиль, стоит ли его изменить или нет. –

+0

Кроме того, модуль тестирует ваш код. Удостоверьтесь, что изменение этих методов не вызвало ничего другого. –

+1

@ L.B Блокировки используются, чтобы сделать определенные операции атомарными. Эти операции связаны с сетевым трафиком, поэтому в значительной степени гарантируется, что они будут быстрее с блокировками RW. Более половины этих операций связаны с чтением удаленного сервера, но некоторые пытаются его написать. – xxbbcc

ответ

1

Является ли статья точной? Я не знаю. Они, по крайней мере, указывают на обновления в .NET, которые решают вопрос, который, по их утверждению, существует, поэтому он предлагает это. С другой стороны, все еще возникает вопрос, применимо ли оно к вам.Настольные компьютеры x86 имеют волатильную семантику для любого доступа к памяти в любом случае, поэтому, если единственная ошибка описывает отсутствие явной нестабильной операции, это не будет проблемой для огромной части оборудования.

На большом серверном оборудовании архитектура отличается, и у них вполне может быть разная семантика, требующая явно нестабильных операций. Это будет то, что вы, возможно, захотите исследовать.

Конечно, независимо от архитектуры оборудования, «volatile» также имеет смысл для компиляторов .NET. Код, цитируемый в статье, мне не кажется, что это повлияет на оптимизацию компилятора, но я не эксперт в этой области, поэтому я не мог сказать точно.

Я принимаю это из-за того, что вы на самом деле не были свидетелями этой ошибки. Это на данный момент чисто гипотетическая проблема.

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

Мой первый выбор состоял бы в том, чтобы убедиться, что я обновился до недавней версии .NET, в которой исправлена ​​ошибка, описанная в статье, на которую вы ссылались.

Второй выбор заключается в использовании простого класса ReaderWriterLock вместо ReaderWriterLockSlim.

Третий вариант заключается в использовании собственной структуры Win32 «slim reader/writer lock» (то есть через p/invoke или C++/CLI).

Только если ни одна из этих опций не оказалась работоспособной, я пойду на проблему, чтобы реализовать свою собственную блокировку чтения-записи, и вы можете поспорить, что я не буду пытаться «тонкий» вариант (т. Е. Со всеми сложными функциями блокировки ... Я мог видеть использование одного летучего флага, но в остальном просто придерживаться обычного кода Monitor).

+0

О, я думаю, что я был недостаточно ясен: я не планирую делать _any_ изменения декомпилированного кода. Я удалил только атрибуты, которые являются внутренними для System.Core. Я не намерен фактически внедрять блокировку RW - я просто хочу исправить одну известную ошибку. – xxbbcc

+0

А, ладно. Теперь я понимаю, что вы имеете в виду. Я думаю, что технически это должно работать нормально. Тем не менее, я все равно не решаюсь это сделать, потому что такая вещь укореняется в базе кода, и вы не получаете преимущества будущих изменений в официальной версии (улучшения производительности или даже исправления ошибок). Вы всегда можете вернуться в будущем, теоретически. Но по какой-то причине на практике это занимает очень много времени. Есть ли причина, по которой вы не хотите или не можете использовать класс ReaderWriterLock? –

+0

Я пытаюсь создать обертку вокруг этого, которая скроет фактический экземпляр блокировки. Таким образом, в будущем, когда ReaderWriterLockSlim фиксируется повсюду (или мы обновляемся до сервера 2012 R2), мне нужно только обновить одно место, чтобы изменить имя типа блокировки от MyRWLock до ReaderWriterLockSlim. Я не могу придумать более безопасное решение в рамках tima, выделенного для этого исправления в моем проекте. – xxbbcc

Смежные вопросы