简体   繁体   English

.Net 4.0并行编程-如何将数据写入并发集合?

[英].Net 4.0 Parallel Programming - how to write data to concurrent collections?

I have a grid which is defined as: List<List<Cell>> , where "Cell" is a custom class of mine. 我有一个定义为: List<List<Cell>>的网格,其中“ Cell”是我的自定义类。 My program has several threads which access various coordinates on the grid, and change data in the "Cell" class. 我的程序有几个线程,这些线程可以访问网格上的各种坐标,并可以更改“ Cell”类中的数据。 But I only want one thread writing data to a "Cell" object at a time. 但是我只希望一个线程一次将数据写入“ Cell”对象。 I thought using concurrent collections such as ConcurrentBag would be of service, but it seems that all the Concurrent Collections only have methods to ADD items or REMOVE them from the collection. 我以为使用并发集合(例如ConcurrentBag)是有用的,但是似乎所有并发集合都只有添加或删除集合中项目的方法。 There doesn't seem to be a thread-safe way to CHANGE data held within such a collection. 似乎没有一种线程安全的方法来更改此类集合中保存的数据。

Am I missing something here, or is there no "easy way" to do it using such collections? 我是否在这里缺少某些东西,或者没有使用这些集合的“简便方法”?

You can simply use mutexes for thread-safe access to your cell contents. 您只需使用互斥锁即可对单元格内容进行线程安全访问。 It works something like this: 它的工作原理如下:

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();
    }

   }

See http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx for more details. 有关更多详细信息,请参见http://msdn.microsoft.com/zh-cn/library/system.threading.mutex.aspx

Have you read this paper? 你读过这篇文章吗?

Thread-safe Collections in .NET Framework 4 and Their Performance Characteristics .NET Framework 4中的线程安全集合及其性能特征

Sample code using ConcurrentBag : 使用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
}

You can also take a look at ConcurrentDictionary's support for adding and updating . 您还可以查看ConcurrentDictionary对添加和更新的支持

The concurrent collections were intended as a means of safely modifying the collection itself; 并发收集旨在作为安全修改收集本身的一种手段。 not the items . 不是物品 You will have to add your own synchronization primitives to the Cell class. 您将必须将自己的同步原语添加到Cell类。 If the outer and inner List instances themselves will remain unchanged there is no need to apply synchronization to them. 如果外部和内部List实例本身将保持不变,则无需对其应用同步。

You mentioned that you will have many readers, but only one writer. 您提到您将有许多读者,但只有一位作家。 That is an incredibly important detail. 这是一个非常重要的细节。 It means that any lock-free synchronization strategies become dramatically easier to implement. 这意味着任何无锁同步策略都变得非常容易实现。 However, I do not encourage going down that route as it would still be quite difficult to get right. 但是,我不鼓励您沿着那条路走,因为要正确行事仍然很困难。 But, it could also mean that the ReaderWriterLockSlim might perform better than a lock . 但是,这也可能意味着ReaderWriterLockSlim 可能lock更好。

You will have to experiment with both to see which one provides the best balance of maintainability and efficiency. 您将不得不对两者进行试验,以查看哪种方法在可维护性和效率之间达到最佳平衡。 My hunch is that you will find a traditional lock will perform faster despite having multiple readers and a single writer, but it is worth testing. 我的直觉是,尽管有多个读取器和一个写入器,您会发现传统lock执行速度更快,但是值得测试。 It is certainly a lot easier on the fingers when typing out the code. 键入代码时,手指上的操作当然容易得多。

Here is sample code for both. 这是两者的示例代码。

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.
    }    
  }
}

and

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();
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM