#c# #.net #wcf #web-services #thread-safety
#c# #.net #wcf #веб-службы #безопасность потоков
Вопрос:
Я создаю библиотеку служб WCF, и у меня есть вопрос относительно безопасности потоков, использующих метод внутри этой библиотеки, вот полная реализация, которая у меня есть до сих пор.
namespace WCFConfiguration
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class ConfigurationService : IConfigurationService
{
ConcurrentDictionary<Tuple<string,string>, string> configurationDictionary = new ConcurrentDictionary<Tuple<string,string>, string>();
public void Configuration(IEnumerable<Configuration> configurationSet)
{
Tuple<string, string> lookupStrings;
foreach (var config in configurationSet)
{
lookupStrings = new Tuple<string, string>(config.BoxType, config.Size);
configurationDictionary.TryAdd(lookupStrings, config.RowNumber);
}
}
public void ScanReceived(string boxType, string size, string packerId = null)
{
}
}
}
Представьте, что у меня есть 10 значений в моем configurationDictionary, и многие люди хотят запросить этот метод ScanReceived, использующий словарь, являются ли эти 10 значений общими для каждого из клиентов, которые запрашивают ScanReceived? Нужно ли мне менять свое поведение в отношении обслуживания?
Кстати, метод настройки используется только одним человеком.
Комментарии:
1. Ваша служба имеет режим ConcurrencyMode. Одиночный, поэтому у вас не возникнет проблем с параллелизмом. Кроме того, ScanReceived не имеет кода, поэтому я уверен, что вы будете в безопасности, вызывая метод no-op, возвращающий void.
2. Я все еще работаю над кодом ScanReceived, но он изменится на int.
Ответ №1:
С InstanceContextMode
помощью of PerCall
вы должны получать новый экземпляр вашей службы и вашего словаря каждый раз, когда поступает удаленный вызов (который, я предполагаю, будет либо Configuration()
или ScanReceived()
). Это не будет использоваться configurationDictionary
несколькими клиентами.
С помощью a ConcurrencyMode
of Single
у вас будет только один поток, выполняющий ваш код одновременно. Таким образом, любые проблемы параллелизма являются спорными.
Два способа совместного использования configurationDictionary
:
- Сделайте его статическим:
private readonly static ConcurrentDictionary<...> ...
- Измените свой
InstanceContextMode
и, возможно, вашConcurrencyMode
.
Я бы рекомендовал первый вариант, если вы не ожидаете тысяч обращений к вашей службе в секунду.
В MSDN есть некоторая информация о InstanceContextMode и создании экземпляров классов служб.
Если вы измените на InstanceContextMode.Single
и ConcurrencyMode.Multiple
, вы можете получить много потоков, выполняющихся одновременно, и вам нужно будет беспокоиться о синхронизированном доступе.
Главное, на что следует обратить внимание, это то, что когда вы запрашиваете / перебираете свой словарь, кто-то другой может его изменить. Получение моментального снимка словаря и затем запрос моментального снимка должны решить эту проблему:
foreach (var x in configurationDictionary.ToArray())
{
....
}
Или, если вы используете LINQ:
var someResult = configurationDictionary.ToArray().Where(...).Select(...)
Комментарии:
1. Я не знаю, сколько вызовов я собираюсь получить, но я почти уверен, что это будет сделано в порядке, мне рекомендовали сделать для этого синглтон, но я не знаю, хороший ли это подход.
2. что, если я установлю свойство следующим образом: [ServiceBehavior(InstanceContextMode = InstanceContextMode. Одиночный, ConcurrencyMode = ConcurrencyMode. Одиночный)] ??
3. Оба single означают один экземпляр вашего класса обслуживания и только один поток. Подразумевается, что вы можете обслуживать только один запрос за раз. Это означает отсутствие проблем с параллелизмом, но ваша служба не может поддерживать большое количество клиентов (я думаю, что запросы ставятся в очередь, если один из них уже выполняется).
4. Итак, короче говоря, оба одиночных будут в порядке для ваших целей, если у вас всего несколько клиентов.
5. Я не знаю, стоит ли упоминать об этом, но метод ScanRecieved будет отправлять строку по TCP-соединению на принтер обрабатываемого устройства, поэтому мне нужно было быть в последовательности.