Параллельное программирование.Net 4.0 - как записать данные в параллельные коллекции?
У меня есть сетка, которая определяется как: List<List<Cell>>
, где "Cell" - мой пользовательский класс. Моя программа имеет несколько потоков, которые получают доступ к различным координатам в сетке и изменяют данные в классе "Ячейка". Но я хочу, чтобы только один поток записывал данные в объект "Cell" за раз. Я думал, что использование параллельных коллекций, таких как ConcurrentBag, будет полезным, но кажется, что у всех параллельных коллекций есть только методы ДОБАВИТЬ элементы или УДАЛИТЬ их из коллекции. Кажется, не существует поточно-безопасного способа ИЗМЕНЕНИЯ данных, хранящихся в такой коллекции.
Я что-то здесь упускаю или нет "простого способа" сделать это с помощью таких коллекций?
3 ответа
Вы можете просто использовать мьютексы для потокового доступа к содержимому вашей ячейки. Это работает примерно так:
class Cell{
private static Mutex mut = new Mutex();
private static void SetResource(...)
{
// Wait until it is safe to enter.
mut.WaitOne();
//change cell contents here...
// Release the Mutex.
mut.ReleaseMutex();
}
}
См. http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx для получения дополнительной информации.
Вы читали эту статью?
Потокобезопасные коллекции в.NET Framework 4 и их характеристики производительности
Пример кода с использованием ConcurrentBag
:
if (bag.TryTake(out node))
{
for (int i = 0; i < node.Children.Count; i++)
{
bag.Add(node.Children[i]);
}
ProcessNode(node); //e.g. a short string comparison
}
Вы также можете взглянуть на поддержку ConcurrentDictionary для добавления и обновления.
Параллельные коллекции были задуманы как средство безопасного изменения самой коллекции; не предметы. Вы должны будете добавить свои собственные примитивы синхронизации к Cell
учебный класс. Если внешнее и внутреннее List
сами экземпляры останутся без изменений, поэтому нет необходимости применять к ним синхронизацию.
Вы упомянули, что у вас будет много читателей, но только один писатель. Это невероятно важная деталь. Это означает, что любые стратегии синхронизации без блокировки становятся значительно проще в реализации. Тем не менее, я не рекомендую идти по этому пути, так как все равно было бы довольно сложно получить права. Но это также может означать, что ReaderWriterLockSlim
может работать лучше, чем lock
,
Вам придется поэкспериментировать с обоими, чтобы увидеть, какой из них обеспечивает лучший баланс удобства обслуживания и эффективности. Я догадываюсь, что вы найдете традиционный lock
будет работать быстрее, несмотря на наличие нескольких читателей и одного писателя, но это стоит проверить. Это, конечно, намного проще при наборе кода.
Вот пример кода для обоих.
public class Cell
{
private object m_LockObject = new object();
public object ReadMyState()
{
lock (m_LockObject)
{
// Return the data here.
}
}
public void ChangeMyState()
{
lock (m_LockObject)
{
// Make your changes here.
}
}
}
а также
public class Cell
{
private ReaderWriterLockSlim m_LockObject = new ReaderWriterLockSlim();
public object ReadMyState()
{
m_LockObject.EnterReadLock();
try
{
// Return the data here.
}
finally
{
m_LockObject.ExitReadLock();
}
}
public void ChangeMyState()
{
m_LockObject.EnterWriteLock();
try
{
// Make your changes here.
}
finally
{
m_LockObject.ExitWriteLock();
}
}
}