Параллельное программирование.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();
    }
  }
}
Другие вопросы по тегам