C# 在方法的一个实例上操作的线程
我正在创建一个应用程序,其中我有50x50地图。在这张地图上我可以添加点,它们是类“点”的新实例。每个点都有自己的线程,每个与特定点连接的线程都在类的“explore”方法上运行,在这个方法中还有另一个方法“check_place(x,y)”,它负责检查地图上的某个地方是否已经被发现。如果不是,则类“num_discovered”的静态变量应该递增。应用程序中启动的每个线程都应该实时访问“check_place(x,y)”方法的单个实例 建造商:C# 在方法的一个实例上操作的线程,c#,multithreading,mutex,C#,Multithreading,Mutex,我正在创建一个应用程序,其中我有50x50地图。在这张地图上我可以添加点,它们是类“点”的新实例。每个点都有自己的线程,每个与特定点连接的线程都在类的“explore”方法上运行,在这个方法中还有另一个方法“check_place(x,y)”,它负责检查地图上的某个地方是否已经被发现。如果不是,则类“num_discovered”的静态变量应该递增。应用程序中启动的每个线程都应该实时访问“check_place(x,y)”方法的单个实例 建造商: public dot(Form1 F) {
public dot(Form1 F)
{
/...
thread = new System.Threading.Thread(new System.Threading.ThreadStart(explore)); //wątek wykonujący metodę explore klasy robot
thread.Start();
}
检查位置(x,y)方法:
在explore方法中,我调用方法“check_place(x,y)”,如下所示:
dot.check_place(x, y);
如果一次只有一个点可以检查位置是否已被发现,这是否足以实现这种情况?您在这方面的性能可能非常差-我建议使用Task.Run here,以便在需要在多个线程上并行运行explore方法时提高效率 就锁定和线程安全而言,如果在check_place中锁定是您在discovered变量中设置bools并设置num_discovered变量的唯一位置,那么现有代码将起作用。如果您从代码中的其他地方开始设置它们,那么您也需要在那里使用锁 此外,在读取这些变量时,您应该使用相同的锁对象将这些值读入其他锁内的局部变量,以维护线程安全
我还有其他建议,但这是您在这里需要的两个最基本的东西。您在这方面的性能可能非常差-我建议使用Task.Run here,以便在需要在多个线程上并行运行explore方法时提高效率 就锁定和线程安全而言,如果在check_place中锁定是您在discovered变量中设置bools并设置num_discovered变量的唯一位置,那么现有代码将起作用。如果您从代码中的其他地方开始设置它们,那么您也需要在那里使用锁 此外,在读取这些变量时,您应该使用相同的锁对象将这些值读入其他锁内的局部变量,以维护线程安全 我还有其他建议,但这是你在这里需要的两个最基本的东西 这是否足以实现一种情况,即在单一时间内只有一个点可以检查该位置是否已被发现 对。但这有什么意义呢 如果线程将所有时间都花在等待其他线程上,那么多线程有什么好处呢 产生更多线程的原因有三个(有时是重叠的):
static void check_place(int x, int y)
{
if (!discovered[x, y])
lock (ob)
if (!discovered[x, y])
{
discovered[x, y] = true;
num_discovered += 1;
}
}
现在,至少有些线程会跳过某些情况,discovered[x,y]
为true
,而不占用其他线程
当线程将在锁定周期结束时获得结果时,这非常有用。不过,这还不够好,因为如果它再次争夺锁,它将很快进入一个案例
如果我们对的查找发现本身是线程安全的,并且线程安全是细粒度的,那么我们可以取得一些进展:
static void check_place(int x, int y)
{
if (discovered.SetIfFalse(x, y))
Interlocked.Increment(ref num_discovered)
}
到目前为止,尽管我们刚刚解决了这个问题;如何使SetIfFalse
线程安全,而不使用单个锁并导致相同的问题
有几种方法。我们可以使用条带锁或低锁并发集合
看起来您有一个50×50的固定大小结构,在这种情况下,这并不难:
private class DotMap
{
//ints because we can't use interlocked with bools
private int[][] _map = new int[50][];
public DotMap()
{
for(var i = 0; i != 50; ++i)
_map[i] = new int[50];
}
public bool SetIfFalse(int x, int y)
{
return Interlocked.CompareExchange(ref _map[x][y], 1, 0) == 0;
}
}
现在我们的优势是:
我们所有的锁定级别都要低得多(但请注意,联锁的
操作在遇到争用时仍然会减慢,尽管不如锁定
)
我们的大部分锁定都是以其他锁定方式实现的。具体地说,在SetIfFalse
中,可以允许对单独的区域进行检查,而无需相互检查
但这既不是万灵药(此类方法在面临争议时仍会受到影响,也会带来自身的成本),也不容易推广到其他情况(将SetIfFalse
更改为只检查和更改单个值并不容易)。即使在拥有大量内核的机器上,这也很可能比单线程方法慢
阿诺特
private class DotMap
{
//ints because we can't use interlocked with bools
private int[][] _map = new int[50][];
public DotMap()
{
for(var i = 0; i != 50; ++i)
_map[i] = new int[50];
}
public bool SetIfFalse(int x, int y)
{
return Interlocked.CompareExchange(ref _map[x][y], 1, 0) == 0;
}
}