Как сделать потокобезопасный Dictionary
От: Аноним  
Дата: 19.10.10 18:03
Оценка:
Есть метод DoSomething в котором происходит асинхронный запрос к БД для работы с объектом имеющего уникальный ID, нужно чтобы пока обрабатывается объект новый асинхронный запрос не прошел.


public static void DoSomething( int ID )
{
   /// Здесь асинхронный вызов некой хранимки с передачей ей ID,
}

public static void DoSomethingFinished( .. )
{
  /// Здесь получаем результаты асинхронного запроса
}



т.е. нужно немного доработать , примерно так


private static Dictionary<int, bool> m_InProc;

public static void DoSomething( int ID )
{
   if ( m_InProc.ContainKey( ID ) )
   {
      if ( m_InProc[ID] )
         return;
   }

   m_InProc[ID] = true;
   /// Здесь асинхронный вызов некой хранимки с передачей ей ID,
}

public static void DoSomethingFinished( .. )
{
  /// Здесь получаем результаты асинхронного запроса
  m_InProc[ID] = false;
}


Возможно для этих целей лучше использовать какие-то объекты синхронизации ( мутекс и т.п. ).
Re: Как сделать потокобезопасный Dictionary
От: Аноним  
Дата: 19.10.10 18:32
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Есть метод DoSomething в котором происходит асинхронный запрос к БД для работы с объектом имеющего уникальный ID, нужно чтобы пока обрабатывается объект новый асинхронный запрос не прошел.


А>[c#]


Как то странно получается: "Синхронный запрос через асинхронные методы" В чём фишка?
Re[2]: Как сделать потокобезопасный Dictionary
От: Аноним  
Дата: 19.10.10 18:40
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Аноним, Вы писали:


А>>Есть метод DoSomething в котором происходит асинхронный запрос к БД для работы с объектом имеющего уникальный ID, нужно чтобы пока обрабатывается объект новый асинхронный запрос не прошел.


А>>[c#]


А>Как то странно получается: "Синхронный запрос через асинхронные методы" В чём фишка?


Нет это не синхронный запрос, если заметили то там просто return.
То есть если 2 потока пихнут на обработку одинаковый ID, например =1 , то пока первый обрабатывается второй будет игнорироваться, процедура не "зависает" как при синхронном запросе , а просто игнорирует дублирующий запрос.
При этом 2й поток может послать DoSomething(2) и DoSomething(3) которые будут работать паралельно с DoSomething(1)

Или один поток может вызвать DoSomething(1) и через некоторое время послать DoSomething(2), DoSomething(3) и еще раз DoSomething(1) , а первый запрос еще может не завершится.
Re[3]: Как сделать потокобезопасный Dictionary
От: victor_kr Украина  
Дата: 19.10.10 21:08
Оценка:
Я не профессионал многопоточности, но возможно, можно сделать так.

Создать объект для блокировки:

private static object dictionaryLock = new object();

Обернуть все обращения к dictionary конструкцией lock (dictionaryLock) {...}.

Таким образом вы сделаете работу с dictionary потокобезопасной. Остальная часть кода (длительно выполняющаяся) будет запускаться однократно для каждого ID только после потокобезопасной проверки словаря.
Re[4]: Как сделать потокобезопасный Dictionary
От: Аноним  
Дата: 20.10.10 04:01
Оценка:
Здравствуйте, victor_kr, Вы писали:

_>Я не профессионал многопоточности, но возможно, можно сделать так.


_>Создать объект для блокировки:


_>private static object dictionaryLock = new object();


_>Обернуть все обращения к dictionary конструкцией lock (dictionaryLock) {...}.


_>Таким образом вы сделаете работу с dictionary потокобезопасной. Остальная часть кода (длительно выполняющаяся) будет запускаться однократно для каждого ID только после потокобезопасной проверки словаря.


Интересно, а у object вроде бы нет свойств типа "сигнальное состояние". Соотвественно lock( myobject ) наверное управляет состоянием посредством ссылки на object , а сам object при этом не затрагивается . Почему бы в таком случае не лочить сразу статический объект Dictionary , т.е.

lock( myDictionary )
{
  /// работа с  myDictionary.
}
Re[5]: Как сделать потокобезопасный Dictionary
От: microcod США www.tehnoromantik.net
Дата: 20.10.10 05:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, victor_kr, Вы писали:


_>>Я не профессионал многопоточности, но возможно, можно сделать так.


_>>Создать объект для блокировки:


_>>private static object dictionaryLock = new object();


_>>Обернуть все обращения к dictionary конструкцией lock (dictionaryLock) {...}.


_>>Таким образом вы сделаете работу с dictionary потокобезопасной. Остальная часть кода (длительно выполняющаяся) будет запускаться однократно для каждого ID только после потокобезопасной проверки словаря.


А>Интересно, а у object вроде бы нет свойств типа "сигнальное состояние". Соотвественно lock( myobject ) наверное управляет состоянием посредством ссылки на object , а сам object при этом не затрагивается . Почему бы в таком случае не лочить сразу статический объект Dictionary , т.е.

А>

А>lock( myDictionary )
А>{
А>  /// работа с  myDictionary.
А>}

А>


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

lock(var_1){
lock(var_2){
    //здесь потокобезопасный 
    //доступ к var_1 и var_2
  }
}

Программа — мысли спрессованные в код.
Re[5]: Как сделать потокобезопасный Dictionary
От: GlebZ Россия  
Дата: 20.10.10 06:54
Оценка:
Здравствуйте, Аноним, Вы писали:

Вероятнее всего можно, но так не принято. Объект может локироваться самим объектом, либо другим чужим или полузабытым кодом. Что может привести к дедлокам. Поэтому принято локировать явно через свои object.
Re: Как сделать потокобезопасный Dictionary
От: TK Лес кывт.рф
Дата: 20.10.10 07:37
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Возможно для этих целей лучше использовать какие-то объекты синхронизации ( мутекс и т.п. ).


Для этих целей можно взять ReaderWriterLock. Dictionary потокобезопасна для чтения.

A Dictionary(Of TKey, TValue) can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: Как сделать потокобезопасный Dictionary
От: Lloyd Россия  
Дата: 20.10.10 07:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Возможно для этих целей лучше использовать какие-то объекты синхронизации ( мутекс и т.п. ).


Посмотрите ReaderWriterLockSlim. Там в примерах как раз рассмотрен ваш случай.
Re[5]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 20.10.10 08:19
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Интересно, а у object вроде бы нет свойств типа "сигнальное состояние". Соотвественно lock( myobject ) наверное управляет состоянием посредством ссылки на object , а сам object при этом не затрагивается . Почему бы в таком случае не лочить сразу статический объект Dictionary


Потому что очень бывает полезно читать, хотя бы документацию:

In general, avoid locking on a public type, or instances beyond your code's control.

Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.

Help will always be given at Hogwarts to those who ask for it.
Re[2]: Как сделать потокобезопасный Dictionary
От: Lexey Россия  
Дата: 20.10.10 15:04
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Посмотрите ReaderWriterLockSlim. Там в примерах как раз рассмотрен ваш случай.


У Joe Duffy в блогах было неплохое сравнение реализаций разных ReaderWriter'ов, критической секции и спинлоков. Вывод довольно забавный: readerwriter'ы в случае частой записи прилично сливают обычным критическим секциям и спинлокам.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[6]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 20.10.10 20:02
Оценка: +1
Здравствуйте, GlebZ, Вы писали:

GZ>Вероятнее всего можно, но так не принято. Объект может локироваться самим объектом, либо другим чужим или полузабытым кодом. Что может привести к дедлокам. Поэтому принято локировать явно через свои object.


Это кем так принятно? Если мне память не изменяет, в гайдлайнах наоборот написано, чтобы сами классы не лочились на this — именно потому, что на них может лочиться внешний код. Вы не предлагаете просто плодить сущности (помимо комплекта полей-данных иметь параллельный комплект полей-"локеров" и не забывать всё это поддерживать тоже параллельно)...
[КУ] оккупировала армия.
Re[6]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 20.10.10 20:05
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

_FR>

_FR>In general, avoid locking on a public type, or instances beyond your code's control.
_FR>…
_FR>Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.


Насколько я понял, это относится к дизайну библиотек (потому что у "конечного" кода не может быть "instances beyond your code's control"). Соответственно не рекомендуют лочиться в библиотеках именно потому, что вызывающий код может (и будет) лочиться на них. Не зря же упомянули только публичные типы
[КУ] оккупировала армия.
Re[6]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 20.10.10 20:09
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

Кстати в одной ссылке от вашей страницы как раз и написано (http://msdn.microsoft.com/en-us/library/ms173179.aspx ):

Strictly speaking, the object provided is used solely to uniquely identify the resource being shared among multiple threads, so it can be an arbitrary class instance. In practice, however, this object usually represents the resource for which thread synchronization is necessary. For example, if a container object is to be used by multiple threads, then the container can be passed to lock, and the synchronized code block following the lock would access the container. As long as other threads locks on the same contain before accessing it, then access to the object is safely synchronized.

[КУ] оккупировала армия.
Re: Как сделать потокобезопасный Dictionary
От: Jolly Roger  
Дата: 21.10.10 02:53
Оценка:
Здравствуйте, Аноним, Вы писали:

А сам словарь требует защиты? То есть возможно-ли добавление-удаление в него элементов из разных потоков, или, допустим одновременно с вызовом DoSomething или DoSomethingFinished? Если нет, синхронизировать доступ к словарю нет смысла.

Если есть возможность расширить хранящиеся объекты, то можно добавить им методы Acquire-Release. Если возможности нет, можно создать контейнер для хранения их в словаре, типа
private class DictItem<T>
{
    private int _locked;
    public bool Acquire(){return 0 == Interlocked.Exchenge(ref _locked, 1);}
    public void Release(){Interlocked.Exchenge(ref _locked, 0);}
    public T Item;
}

Можно конечно хранить состояние в отдельном массиве, но лично мне это не нравится. Признаться, мне эта ситуация вообще не нравится, боюсь, в будущем она может создать немало проблем, но Вам на месте должно быть виднее.
"Нормальные герои всегда идут в обход!"
Re[7]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 03:54
Оценка:
Здравствуйте, koandrew, Вы писали:

_FR>>In general, avoid locking on a public type, or instances beyond your code's control.
_FR>>…
_FR>>Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.


K>Насколько я понял, это относится к дизайну библиотек (потому что у "конечного" кода не может быть "instances beyond your code's control").


Я почему-то не знаю, что такое "конечный код" и чем он отличается от какого-то другого кода.

K>Соответственно не рекомендуют лочиться в библиотеках именно потому, что вызывающий код может (и будет) лочиться на них. Не зря же упомянули только публичные типы


Почему слово public обязательно следует понимать буквально? Ничто не мешает понимать его как видимое где-то снаружи.
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 04:08
Оценка: +1
Здравствуйте, koandrew, Вы писали:

K>Кстати в одной ссылке от вашей страницы как раз и написано (http://msdn.microsoft.com/en-us/library/ms173179.aspx ):

K>

Strictly speaking, the object provided is used solely to uniquely identify the resource being shared among multiple threads, so it can be an arbitrary class instance. In practice, however, this object usually represents the resource for which thread synchronization is necessary. For example, if a container object is to be used by multiple threads, then the container can be passed to lock, and the synchronized code block following the lock would access the container. As long as other threads locks on the same contain before accessing it, then access to the object is safely synchronized.


В документации к goto приведено несколько сценариев его использования, но, подходя к програмированию разумно, не все их следует использовать, тем более, повсеместно. Так же и здесь: если дана ссылку на какую-то цитату, это вовсе не означает, что всё произведение в целом есть истина.

В МСДН есть не мало очень умных мыслей. А есть и просто вредные.

В примере в статье, на которую вы ссылаетесь (как, кажется, и везде в МСДН), lockThis даже без ридлонли объявлен — что конечно же никак не влият на _работоспособность_ кода, но может оказаться весьма важным при использовании/поддержке/рефакторинге/переписывании.

Например, в данной статье никак не сказано, как процитированный кусок сочитается с SRP, однако весьма разумно держать это у себя в голове постоянно, и экземпляры объектов (" container object") использовать для одних целей (для которых они напрямую предназначены), а для синхронизации использовать нечто другое, самостоятельное.
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Как сделать потокобезопасный Dictionary
От: Константин Л. Франция  
Дата: 21.10.10 11:46
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Здравствуйте, GlebZ, Вы писали:


GZ>>Вероятнее всего можно, но так не принято. Объект может локироваться самим объектом, либо другим чужим или полузабытым кодом. Что может привести к дедлокам. Поэтому принято локировать явно через свои object.


K>Это кем так принятно? Если мне память не изменяет, в гайдлайнах наоборот написано, чтобы сами классы не лочились на this — именно потому, что на них может лочиться внешний код. Вы не предлагаете просто плодить сущности (помимо комплекта полей-данных иметь параллельный комплект полей-"локеров" и не забывать всё это поддерживать тоже параллельно)...


1. многими
2. это не "плодить сущности", это писать безопасный код
Re[7]: Как сделать потокобезопасный Dictionary
От: Константин Л. Франция  
Дата: 21.10.10 11:47
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Здравствуйте, _FRED_, Вы писали:


_FR>>

_FR>>In general, avoid locking on a public type, or instances beyond your code's control.
_FR>>…
_FR>>Best practice is to define a private object to lock on, or a private static object variable to protect data common to all instances.


K>Насколько я понял, это относится к дизайну библиотек (потому что у "конечного" кода не может быть "instances beyond your code's control"). Соответственно не рекомендуют лочиться в библиотеках именно потому, что вызывающий код может (и будет) лочиться на них. Не зря же упомянули только публичные типы


это нормальное требование для любого кода.
Re[8]: Как сделать потокобезопасный Dictionary
От: victor_kr Украина  
Дата: 21.10.10 11:51
Оценка:
Объекты бизнес-логики не стоит использовать для блокировок, так как у них есть свое назначение. Эти объекты могут удаляться/изменяться/пересоздаваться. Объект блокировки создается для того чтобы решать одну задачу — блокировка доступа. Таким образом можно разделить ответственность и избежать проблем. При использовании отдельных блокирующих объектов не нужно помнить о том, что нельзя пересоздать объект бизнес-логики потому что он где-то используется в качестве блокировки.
Re[8]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:01
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>В документации к goto приведено несколько сценариев его использования, но, подходя к програмированию разумно, не все их следует использовать, тем более, повсеместно. Так же и здесь: если дана ссылку на какую-то цитату, это вовсе не означает, что всё произведение в целом есть истина.


_FR>В МСДН есть не мало очень умных мыслей. А есть и просто вредные.


_FR>В примере в статье, на которую вы ссылаетесь (как, кажется, и везде в МСДН), lockThis даже без ридлонли объявлен — что конечно же никак не влият на _работоспособность_ кода, но может оказаться весьма важным при использовании/поддержке/рефакторинге/переписывании.

Всё вышесказанное не имеет отношения к обсуждаемой теме.

_FR>Например, в данной статье никак не сказано, как процитированный кусок сочитается с SRP, однако весьма разумно держать это у себя в голове постоянно, и экземпляры объектов (" container object") использовать для одних целей (для которых они напрямую предназначены), а для синхронизации использовать нечто другое, самостоятельное.

SRP тут не нарушается, потому что тот факт, что мы на нём лочимся, никак не меняет его функционал — просто делает _наш код_ потокобезопасным.
[КУ] оккупировала армия.
Re[8]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:03
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Почему слово public обязательно следует понимать буквально? Ничто не мешает понимать его как видимое где-то снаружи.


А что кроме public является "видимым где-то снаружи"? Снаружи чего кстати?
[КУ] оккупировала армия.
Re[8]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:03
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>1. многими

КЛ>2. это не "плодить сущности", это писать безопасный код

Аргументация?
[КУ] оккупировала армия.
Re[8]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:04
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>это нормальное требование для любого кода.


Что именно является "нормальным требованием для любого кода"? Аргументы?
[КУ] оккупировала армия.
Re[9]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 12:12
Оценка:
Здравствуйте, koandrew, Вы писали:

_FR>>В документации к goto приведено несколько сценариев его использования, но, подходя к програмированию разумно, не все их следует использовать, тем более, повсеместно. Так же и здесь: если дана ссылку на какую-то цитату, это вовсе не означает, что всё произведение в целом есть истина.

_FR>>В МСДН есть не мало очень умных мыслей. А есть и просто вредные.
_FR>>В примере в статье, на которую вы ссылаетесь (как, кажется, и везде в МСДН), lockThis даже без ридлонли объявлен — что конечно же никак не влият на _работоспособность_ кода, но может оказаться весьма важным при использовании/поддержке/рефакторинге/переписывании.
K>Всё вышесказанное не имеет отношения к обсуждаемой теме.

Имеет Я же в ответ на свою цитату получил другую без какого-то бы нибыло разъяснения.

_FR>>Например, в данной статье никак не сказано, как процитированный кусок сочитается с SRP, однако весьма разумно держать это у себя в голове постоянно, и экземпляры объектов (" container object") использовать для одних целей (для которых они напрямую предназначены), а для синхронизации использовать нечто другое, самостоятельное.

K>SRP тут не нарушается, потому что тот факт, что мы на нём лочимся, никак не меняет его функционал — просто делает _наш код_ потокобезопасным.

Чем потокобезопастность нашего кода, в случае использования специального объекта синхронизации будет отличаться? А то, что SRP нарушается видно очень хорошо: при необходимости реализации другого сценария потокобезопастности может потребоваться синхронизироваться по другому объекту. Если одна синхронизация делается на самом неком объекте, а другая — на объекте сбоку, то возникает вопрос — почему по сути одно и то же реализовано по-разному?
Help will always be given at Hogwarts to those who ask for it.
Re[9]: Как сделать потокобезопасный Dictionary
От: Константин Л. Франция  
Дата: 21.10.10 12:16
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Здравствуйте, Константин Л., Вы писали:


КЛ>>1. многими

КЛ>>2. это не "плодить сущности", это писать безопасный код

K>Аргументация?


лочась на объект, для этого не предназначенный, ты повышаешь энтропию. объекты синхронизации это не лишние сущности. я предпочитаю заводить readonly object и спать спокойно.
Re[9]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 12:17
Оценка:
Здравствуйте, koandrew, Вы писали:

_FR>>Почему слово public обязательно следует понимать буквально? Ничто не мешает понимать его как видимое где-то снаружи.


K>А что кроме public является "видимым где-то снаружи"?


Как минимум, то, что называется internal.

K>Снаружи чего кстати?


Снаружи — означает "извне". Чего именно — да чего угодно, никаких не соответствий не вижу.

Например, снаружи вложенного private-класса видны его public-члены, но более "снаружи" уже нет. Попадают ли такие public-члены под термин "public", используемый в гайдлайнах? Чаще всего, нет. Но в некоторой узкой и очень близкой области эпсилон эта непубличность может быть очень даже заметна. Поэтому под "public" в цитате не следует понимать все открытые члены открытых типов, видимые в сторонних сборках. А именно это и подразумевается в MSDN.
Help will always be given at Hogwarts to those who ask for it.
Re[10]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:19
Оценка: -1
Здравствуйте, _FRED_, Вы писали:

_FR>Чем потокобезопастность нашего кода, в случае использования специального объекта синхронизации будет отличаться? А то, что SRP нарушается видно очень хорошо: при необходимости реализации другого сценария потокобезопастности может потребоваться синхронизироваться по другому объекту. Если одна синхронизация делается на самом неком объекте, а другая — на объекте сбоку, то возникает вопрос — почему по сути одно и то же реализовано по-разному?


SRP не про то, что нельзя один и тот же класс использовать для разных целей, он про то, что конкретный экземпляр класса нужно использовать для одной цели. Если определить цель как "потокобезопасная коллекция", то всё встаёт на свои места.
Вообще же в реальности я обычно в таком случае использую потокобезопасные агрегаты коллекций, которые обеспечивают потокобезопасность внутри себя, позволяя освободить внешний код то мусора, вызванного необходимостью синхронизации.
[КУ] оккупировала армия.
Re[10]: Как сделать потокобезопасный Dictionary
От: Константин Л. Франция  
Дата: 21.10.10 12:20
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, koandrew, Вы писали:


_FR>>>Почему слово public обязательно следует понимать буквально? Ничто не мешает понимать его как видимое где-то снаружи.


K>>А что кроме public является "видимым где-то снаружи"?


_FR>Как минимум, то, что называется internal.


K>>Снаружи чего кстати?


_FR>Снаружи — означает "извне". Чего именно — да чего угодно, никаких не соответствий не вижу.


_FR>Например, снаружи вложенного private-класса видны его public-члены, но более "снаружи" уже нет. Попадают ли такие public-члены под термин "public", используемый в гайдлайнах? Чаще всего, нет. Но в некоторой узкой и очень близкой области эпсилон эта непубличность может быть очень даже заметна. Поэтому под "public" в цитате не следует понимать все открытые члены открытых типов, видимые в сторонних сборках. А именно это и подразумевается в MSDN.


+1

я вообще не понимаю какой смысл писать многопоточный код по-разному в зависимости от того, публичный он или нет? писать надо всегда максимально безопасно вне зависимости от purposes.
Re[10]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:24
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>лочась на объект, для этого не предназначенный, ты повышаешь энтропию. объекты синхронизации это не лишние сущности. я предпочитаю заводить readonly object и спать спокойно.


Любой объект предназначен для лока. Энтропия системы остаётся постоянно. А вот добавляя объекты-локеры, ты как раз повышаешь энтропию, ко всему прочему ещё и заставляя поддерживающих твой код быть в курсе того, что для безопасного доступа к объекту Х надо лочиться на объекте Y. Эти объекты никак не связаны друг с другом, а посему саппортерами нужно будет разбираться во всём коде, чтобы увидеть эту связь. В то время как знание о том, что для обеспечения синхронизированного доступа к объекту нужно на нём залочиться, даётся MSDN'ом и всеми книжками по языку и библиотеке, так что мы вправе принять наличие этого знания как данность.
[КУ] оккупировала армия.
Re[10]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 12:27
Оценка:
Здравствуйте, _FRED_, Вы писали:

K>>А что кроме public является "видимым где-то снаружи"?


_FR>Как минимум, то, что называется internal.


K>>Снаружи чего кстати?


_FR>Снаружи — означает "извне". Чего именно — да чего угодно, никаких не соответствий не вижу.


_FR>Например, снаружи вложенного private-класса видны его public-члены, но более "снаружи" уже нет. Попадают ли такие public-члены под термин "public", используемый в гайдлайнах? Чаще всего, нет. Но в некоторой узкой и очень близкой области эпсилон эта непубличность может быть очень даже заметна. Поэтому под "public" в цитате не следует понимать все открытые члены открытых типов, видимые в сторонних сборках. А именно это и подразумевается в MSDN.


Под "публичностью" в процитированной мною (да и тобой) статье подразумевается "доступность из кода, который использует ваш класс и при этом неподконтролен вам". По-моему достаточно чёткое определение, и под него чаще всего попадают именно public-члены.
[КУ] оккупировала армия.
Re[11]: Как сделать потокобезопасный Dictionary
От: Константин Л. Франция  
Дата: 21.10.10 12:35
Оценка: +1
Здравствуйте, koandrew, Вы писали:

K>Здравствуйте, Константин Л., Вы писали:


КЛ>>лочась на объект, для этого не предназначенный, ты повышаешь энтропию. объекты синхронизации это не лишние сущности. я предпочитаю заводить readonly object и спать спокойно.


K>Любой объект предназначен для лока.


случайность и сахар. я бы его убрал, кстати

K>Энтропия системы остаётся постоянно.


ну уж нет

K>А вот добавляя объекты-локеры, ты как раз повышаешь энтропию, ко всему прочему ещё и заставляя поддерживающих твой код быть в курсе того, что для K>безопасного доступа к объекту Х надо лочиться на объекте Y.


да, еще имена переменным обычно дают отличные от apsidlasjdhjy. черт,, это все вообще не проблема

K>Эти объекты никак не связаны друг с другом, а посему саппортерами нужно будет разбираться во всём коде, чтобы увидеть эту связь.


да, в таком коде нужно разбираться неделями (псевдокод):


        readonly HashSet<long> InProgress = new HashSet<long>();
        readonly object InProgressSync = new object();

bool SetInProgress(long id)
        {
            lock (InProgressSync)
            {
                if (InProgress.Contains(id))
                    return false;

                InProgress.Add(id);
                return true;
            }
        }


с чем тут надо разбираться?

K>В то время как знание о том, что для обеспечения синхронизированного доступа к объекту нужно на нём залочиться, даётся MSDN'ом и всеми K>книжками по языку и библиотеке, так что мы вправе принять наличие этого знания как данность.


частный случай. обычно лочат код, а не объекты. лочить объекты дурной тон. лочить нужно код
Re[11]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 12:37
Оценка:
Здравствуйте, koandrew, Вы писали:

_FR>>Чем потокобезопастность нашего кода, в случае использования специального объекта синхронизации будет отличаться? А то, что SRP нарушается видно очень хорошо: при необходимости реализации другого сценария потокобезопастности может потребоваться синхронизироваться по другому объекту. Если одна синхронизация делается на самом неком объекте, а другая — на объекте сбоку, то возникает вопрос — почему по сути одно и то же реализовано по-разному?


K>SRP не про то, что нельзя один и тот же класс использовать для разных целей, он про то, что конкретный экземпляр класса нужно использовать для одной цели. Если определить цель как "потокобезопасная коллекция", то всё встаёт на свои места.


Если говорить такой о задаче класса, как "потокобезопастная коллекция", то использование lock(внутреннее хранилище) — это отвратительный дизайн. Кстати, очень хороший пример, что бы объяснить почему.

Итак, у нас есть задача сделать потокобезопастную коллекцию.

В обсуждаемом вопросе у нас есть два пути: послушаться меня и завести отдельно поле для синхронизации и послушаться чего-то ещё и лочится, не заморачиваясь со специальным полем, на имеющееся поле внутреннего хранилища. Работать два варианта буду одинаково. Прекрасно.

Теперь вспомним, о чём я предупреждал и посмотрим, что в [интерфейсе] нашей коллекции можно улучшить. Казалось бы — ничего? Коллекция она и есть коллекция и со времён первого фреймворка принципиально не менялась? Ан нет. Есть одно отличие, связанное как раз с многопоточностью: из коллекции ушло свойство SyncRoot. Ушло потому, что во многих сценариях требуется извне задать коллекции объект, по которому требуется синхронизировать обращение к внутреннему хранилищу.

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

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

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

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


Что есть агрегат коллекции? Вообще, "потокобезопастная коллекция" сама в себе очень не нужна. Потокобезопастными имеет смысл делать не столько объекты, сколько операции, сценарии работы, более общие, чем "добавить сюда элемент".

Но мы же тут не о подходе, а о способе реализации маленькой частички обеспечения синхронности, которая, однако, используется довольно часто.
Help will always be given at Hogwarts to those who ask for it.
Re[11]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 12:41
Оценка:
Здравствуйте, koandrew, Вы писали:

K>>>А что кроме public является "видимым где-то снаружи"?

_FR>>Как минимум, то, что называется internal.
K>>>Снаружи чего кстати?
_FR>>Снаружи — означает "извне". Чего именно — да чего угодно, никаких не соответствий не вижу.
_FR>>Например, снаружи вложенного private-класса видны его public-члены, но более "снаружи" уже нет. Попадают ли такие public-члены под термин "public", используемый в гайдлайнах? Чаще всего, нет. Но в некоторой узкой и очень близкой области эпсилон эта непубличность может быть очень даже заметна. Поэтому под "public" в цитате не следует понимать все открытые члены открытых типов, видимые в сторонних сборках. А именно это и подразумевается в MSDN.

K>Под "публичностью" в процитированной мною (да и тобой) статье подразумевается "доступность из кода, который использует ваш класс и при этом неподконтролен вам". По-моему достаточно чёткое определение, и под него чаще всего попадают именно public-члены.


Я опять же не знаю, что такое "неподконтролен вам". И почему это "подконтрольный мне" код должен делать более предлоложений о работе некоего кода Х чем другой код?
Help will always be given at Hogwarts to those who ask for it.
Re[11]: Как сделать потокобезопасный Dictionary
От: GlebZ Россия  
Дата: 21.10.10 13:53
Оценка:
Здравствуйте, koandrew, Вы писали:

K>SRP не про то, что нельзя один и тот же класс использовать для разных целей, он про то, что конкретный экземпляр класса нужно использовать для одной цели.

Неверное опеределение. Классы могут быть классами-состояния, и классами-поведения. Лочат собственно доступ к ресурсу или набору ресурсов, то есть классу состояния. А он уже используется для разных целей. Поэтому решение как лочить должно лежать на объектах бизнес-логики.

K>Если определить цель как "потокобезопасная коллекция", то всё встаёт на свои места.

Две "потокобезопасных коллекции" уже не являются "потокобезопасными". Сама коллекция может быть потокобезопасна только при атомарных операциях.
Re[12]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 21.10.10 14:07
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Я опять же не знаю, что такое "неподконтролен вам". "Неподконтрольный вам" == "написанный и поддерживаемый не вами (не вашим тимом/компанией)".

_FR>И почему это "подконтрольный мне" код должен делать более предлоложений о работе некоего кода Х чем другой код?
Не должен, но часто делает
[КУ] оккупировала армия.
Re[13]: Как сделать потокобезопасный Dictionary
От: _FRED_ Черногория
Дата: 21.10.10 14:30
Оценка:
Здравствуйте, koandrew, Вы писали:

_FR>>Я опять же не знаю, что такое "неподконтролен вам". "Неподконтрольный вам" == "написанный и поддерживаемый не вами (не вашим тимом/компанией)".

_FR>>И почему это "подконтрольный мне" код должен делать более предлоложений о работе некоего кода Х чем другой код?
K>Не должен, но часто делает

Делает, не поспоришь

Вопрос в том, должен ли ИМХО, не должен. Гораздо меньше мусора и безобразия получается, если не делить код на "наш"/"ваш", "внешний"/"внутренний". ИМХО, это всё оправдания творческой и производственной импотенции.
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Как сделать потокобезопасный Dictionary
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.10.10 18:18
Оценка:
Здравствуйте, Lexey, Вы писали:

L>У Joe Duffy в блогах было неплохое сравнение реализаций разных ReaderWriter'ов, критической секции и спинлоков. Вывод довольно забавный: readerwriter'ы в случае частой записи прилично сливают обычным критическим секциям и спинлокам.


ReaderWriterLockSlim это и есть спинлок.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
AVK Blog
Re[11]: Как сделать потокобезопасный Dictionary
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.10.10 18:18
Оценка:
Здравствуйте, koandrew, Вы писали:

K>SRP не про то, что нельзя один и тот же класс использовать для разных целей, он про то, что конкретный экземпляр класса нужно использовать для одной цели.


Сам придумал? SRP предназначен для декомпозиции предметной области на сущности языка программирования. Экземпляры тут вообще не причем.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
AVK Blog
Re[12]: Как сделать потокобезопасный Dictionary
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 25.10.10 23:02
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Сам придумал? SRP предназначен для декомпозиции предметной области на сущности языка программирования. Экземпляры тут вообще не причем.


А экземпляр — это разве не сущность?
[КУ] оккупировала армия.
Re[13]: Как сделать потокобезопасный Dictionary
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 26.10.10 07:48
Оценка:
Здравствуйте, koandrew, Вы писали:

K>А экземпляр — это разве не сущность?


Экземпляр это не элемент декомпозиции обычно. По крайней мере не в прототипно-ориентированных языках.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
AVK Blog
Re[4]: Как сделать потокобезопасный Dictionary
От: Lexey Россия  
Дата: 26.10.10 16:58
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>ReaderWriterLockSlim это и есть спинлок.


Крайне сомнительно. Классический спинлок — это один флаг. Мультиридеру-же требуется счетчик ридеров.
"Будь достоин победы" (c) 8th Wizard's rule.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.