结构数组,多线程,我可以同时写入不同的索引吗?

时间:2010-07-17 12:26:07

标签: c# multithreading arrays struct thread-safety

我有一个巨大的数组,其中包含一个结构“Tile”。我正在编写的程序是2D游戏,我不希望不同的玩家(由不同的线程处理)同时将他们的位置写入同一个图块,我想知道两件事。两个线程可以安全地同时写入数组中的两个不同位置,是否有一些有效的方法只能锁定该数组的一个索引?

4 个答案:

答案 0 :(得分:2)

是的,你可以从不同的线程同时写入不同的位置。

要进行锁定,您应该创建一个锁数组,并使用一些简单的散列技术根据正在写入的位置选择一个锁。例如:

class TileArray
{
    private static readonly int numLocks = 16;
    private object[] locks = (from i in Range(0, numLocks) select new object()).ToArray();
    private Tile[] tiles = hugeTileArray();

    ...

    public Tile this[int i]
    {
        get { return tiles[i]; }
        set
        {
            lock (locks[i % numLocks])
                tiles[i] = value;
        }
    }
}

这避免了创建数以万计的锁的需要,但仍然将锁争用保持在最低限度。您可以根据分析设置向上或向下设置numLocks。但是,为了进行有效的模运算,保持它是2的幂。

最后一个细节:注意别名效果。例如,由于某些奇怪的原因,16个多个位置可能恰好在您的线程中非常受欢迎,在这种情况下,争用将通过屋顶。如果是这种情况,您将需要更强的哈希值。也许(uint)i.GetHashCode() % numLocks会这样做,但我不确定Int32.GetHashCode会做什么;它可能只返回数字本身。如果做不到这一点,你可以从Bob Jenkins偷走一个。

答案 1 :(得分:1)

您可以使用Interlocked.CompareExchange函数安全地进行读写操作,而无需明确使用锁。

public class Example
{
  private Tile[] m_Array;

  public Tile this[int index]
  {
    get { return Interlocked.CompareExchange(ref m_Array[i], null, null); }
    set { Interlocked.CompareExchange(ref m_Array[i], value, m_Array[i]); }
  }
}

当然,您必须将Tile结构转换为类才能执行此操作。

答案 2 :(得分:0)

没有内置支持您想要做的事情。多个线程可以同时访问同一个阵列,但您需要通过同步等方式自己处理数据一致性。因此,虽然可以实现每索引锁定(类似于数据库在事务中执行的操作),但我不确定这是您正在尝试执行的操作的正确方法。你为什么要使用数组开始?

答案 3 :(得分:0)

我相信你可以使用lock statement使代码线程安全,这是访问数组并在线程之间共享。