Объект Hashtable является безопасным для потоков при использовании несколькими потоками чтения и одним потоком записи. Этот объект безопасен для использования несколькими потоками, когда только один из потоков выполняет операции записи (обновления), что допускает свободное от блокировки чтение при условии, что потоки записи сериализованы в объект Hashtable. Чтобы была поддержка нескольких потоков записи, все операции с потоком Hashtable должны выполняться с использованием оболочки, возвращаемой методом Synchronizedпри условии, что нет ни одного потока, читающего объект Hashtable.
Объясните, пожалуйста, что это означает? :
при условии, что потоки записи сериализованы в объект Hashtable
Нет, как-то не складно получается...
То, что операции записи происходят последовательно, говорит вот это:
когда только один из потоков выполняет операции записи (обновления)
Тогда, получается масло масляное:
когда только один из потоков выполняет операции записи (обновления),
что допускает свободное от блокировки чтение при условии, что потоки записи сериализованы в объект Hashtable.
так как подчеркнутые строчки — это, по сути, одно и то же... Не?
E>когда только один из потоков выполняет операции записи (обновления),
E>что допускает свободное от блокировки чтение при условии,
E>что потоки записи сериализованы в объект Hashtable.
E>так как подчеркнутые строчки — это, по сути, одно и то же... Не?
Чисто формально это не одно и то же, так как во втором случае потоков может быть много, но писать одновременно они не могут. В WinForms например что-то делать с UI контролом из другого потока в принципе нельзя, независимо от наличия других. А здесь можно.
На практике это конечно означает необходимость синхронизации, что сводит пользу от такой возможности на нет
Шурыгин Сергей
"Не следует преумножать сущности сверх необходимости" (с) Оккам
E>>при условии, что потоки записи сериализованы в объект Hashtable
E>>
C>Означает, что для того чтобы потокобезопасно надо
C>При записи в коллекцию делать:
C>Hashtable x = y.Synchronized() C>и далее писать в копию x
C>При чтении получается что-то вроде dirty-read
C>Если надо коммитед рид, то делай и на записи и на чтении:
C>Lock(y.SyncRoot) C>{ C>}
Да! Мне как раз и нужен коммитед рид.
Проблема вот в чем. Каждый объект в таблице имеет свой поток обновления (не выделенный, а из пула потоков).
То есть в каждый момент времени один и тот же элемент из таблицы меняется или читается только одним потоком.
Сделано это просто: для каждого объекта используется очередь Fiber из retlang. Так вот, если я при каждом обращении к хэштаблице
буду ее лочить, то вся эта параллельная обработка объектов в этой таблице идет коту под хвост.
Ладно в момент добавления/удаления элемента из таблицы, я еще могу залочить всю таблицу целиком — это происходит не так часто.
Но вот лочить таблицу при каждом обращении к одному из ее элементов, это губит всю задуманную схему. Как быть то?
E>...Каждый объект в таблице имеет свой поток обновления (не выделенный, а из пула потоков). E>То есть в каждый момент времени один и тот же элемент из таблицы меняется или читается только одним потоком.
... E>Но вот лочить таблицу при каждом обращении к одному из ее элементов, это губит всю задуманную схему. Как быть то?
Лочишь не саму Hashtable, а её специальный объект Hashtable.SyncRoot
Если у тебя с потоками на обновление непосредственно внутри записей всё разрулилось,
то самая большая проблема это добавление/удаление записей в таблице.
Для удаления/добавления используй Monitor, можно сделать так
if (Monitor.TryEnter(MyTable.SyncRoot), 500)
{
// можно добавлять удалятьtry
{
...
}
finally
{
Monitor.Exit(MyTable.SyncRoot); // высвободить важно!!!
}
}
else
{
// Какой-то другой поток удаляет или добавляет новую запись,
// мы даже ждали 500 миллисекунд, но безуспешно, что-то не так
}
Это слегка похоже на джойн в поток, только с лучшим контролем, как успешная,
так и безуспешная попытка обрабатывается
.
Другими словами, насколько потокобезопасно вызывать из разных потоков один и тот же метод объекта, если внутри самого метода уже сделано все потокобезопасно?