使用多核解决迷宫问题?

时间:2011-01-11 02:12:08

标签: multithreading multicore

这个问题很乱,我不需要一个有效的解决方案,我需要一些伪代码。

我将如何解决这个迷宫?这是一个家庭作业问题。我必须从点绿色变为红色。在每一个分支我需要'产生一个线程'并朝着那个方向前进。我需要弄清楚如何变红但我不确定如何避免我已经采取的路径(完成任何路径都没问题,我只是不允许进入圈内)。

下面是我的问题的一个例子,我开始向下移动,我看到一个叉子,所以一个向右,一个向下(或者这个线程可以接受它,这没关系)。现在让我们忽略其余的叉子,然后说一个向右撞击墙壁,向下,撞到墙壁然后向左走,然后向上走。另一个线程下降,撞到墙壁然后一直向前。从不同的侧面开始,底部路径已经进行了两次。

我如何标记此路径?我需要锁吗?这是唯一的方法吗?有无锁解决方案吗?

实施明智我认为我可以拥有这样的迷宫。我不喜欢这个解决方案,因为有很多锁定(假设我在每次读取和写入hasTraverse成员之前锁定)。我不需要使用下面的MazeSegment类,我只是把它作为一个例子来编写。我被允许建造迷宫,但我想要。我想也许解决方案不需要连接路径,这就是麻烦我。也许我可以拆分地图而不是使用下面的格式(这很容易阅读和理解)。但是,如果我知道如何拆分它,我会知道如何解决这个问题。

我如何有效地走这个迷宫?

我收到的唯一提示是不要试图通过重复使用来保存记忆,制作副本。然而,这与订购列表的问题有关,我不认为暗示是暗示这一点。

class MazeSegment
{
    enum Direction { up, down, left, right}
    List<Pair<Direction, MazeSegment*>> ConnectingPaths;
    int line_length;
    bool haveTraverse;
}

MazeSegment root;

class MazeSegment
{
    enum Direction { up, down, left, right}
    List<Pair<Direction, MazeSegment*>> ConnectingPaths;
    bool haveTraverse;
}

void WalkPath(MazeSegment segment)
{
    if(segment.haveTraverse) return;
    segment.haveTraverse = true;
    foreach(var v in segment)
    {
        if(v.haveTraverse == false)
            spawn_thread(v);
    }
}

WalkPath(root);

alt text

4 个答案:

答案 0 :(得分:4)

并行广度优先搜索

首先搜索并行或多线程面包,这基本上就是你正在做的事情。每次你来迷宫中的一个分叉(你可以从几个路径中选择一个),你创建一个新的工作线程继续搜索每个可能的路径并报告哪一个让你到最后。

除了可以并行搜索子树之外,它类似于“简单”广度优先搜索。

如果这是纯树数据结构,则不需要锁定,但由于它是图遍历,因此您需要跟踪被访问的节点。因此,设置每个节点的“访问”标志的代码将需要用锁保护。

这是一个很好的示例程序。它使用音频反馈,因此请确保您的扬声器已开启。

  

http://www.break.com/games/maze15.html

答案 1 :(得分:3)

副手,鉴于上面的结构,我可以通过在每个MazeSegement中添加'int Seen'而不是'bool haveTraverse'来解决这个问题。然后,当您在ConnectedPaths上循环时,可以在'Seen'变量上使用互锁增量,并且如果'Seen'增量返回1(假设Seen初始化为0),则只产生一个线程来获取路径。

所以代码就像

void WalkPath(MazeSegment segment)
{
    foreach(var v in segment.ConnectedPaths)
    {
        if( Interlocked.Increment( &v.Path.Seen ) == 1)
            spawn_thread(v.Path);
    }
}

其他可能尝试采用相同路径的线程应该得到一些&gt; 1。因为interlocked.increment会保证线程安全增量,所以我们不必担心2个线程得到'1'的结果,因此只有一个线程应该采用给定的路径。

答案 2 :(得分:2)

你可以使用通常的“读取,计算新值,比较和交换,重复直到CAS成功”方法来执行此操作,这种方法通常在无锁编程中找到。

迷宫开始时的所有网格方块都应该有一个指针,指示移动到达出口的方向。最初他们都是“未知”。

从出口处走迷宫。在到达的每个方格上,使用compare和swap将“unknown”替换为此线程先前处理的方形的方向。如果CAS失败,你有一个循环,修剪那个分支。如果CAS成功,继续前进。为入口指定方向时,现在可以按照出口的路径进行操作。

答案 3 :(得分:2)

创建一个类(工作者)实例,其中包含到目前为止所采用的路径,并且只能advance()通过指定方向的直线走廊。在每个交叉点,删除在交叉点之前保存路径的工作对象,并创建两个(或三个)新对象,其中包含该路径的副本和不同的转弯。

将这些工作对象放入队列中。注意它们中的每一个是如何独立于另一个的,所以你可以从队列和advance()并行地取几个。您可以创建尽可能多的线程,或根据您拥有的核心数使用线程池。一旦任何工人前进到目的地广场,输出它所拥有的路径,这是一个解决方案。

考虑从出口到入口穿越迷宫。在一个真正的迷宫中,盲目的小巷旨在减慢从进入到退出的动作,但很少相反。

考虑添加循环检测机制,例如通过将构成路径的交叉点与您遇到的交叉点进行比较。

考虑使用手工制作的链表来表示路径。请注意如何将新头部插入链接列表不会更改其余部分,因此您可以与不修改它的其他实例共享尾部。这将减少产生工作人员所需的内存占用和时间(仅在相当大的迷宫时才会显着)。