2008-10-03 62 views
8

我一直在修补BSP树一段时间,并且还在玩线程。当向BSP树添加三角形时,出现了为并行处理数据创建新线程的机会。我应该一起使用线程和递归吗?

 
insert(triangle, bspnode) 
{ 
    .... 
    else if(triangle spans bspnode) 
    { 
    (frontpiece, backpiece) = plane_split(triangle, bspnode) 

    insert(frontpiece, bspnode.front) 
    insert(backpiece, bspnode.back) 
    } 
    .... 
} 

上面的两个插入操作可以由两个线程执行,并且由于它们不修改相同的数据,所以可以使用便宜的同步。

 
insert(triangle, bspnode) 
{ 
    .... 
    else if(triangle spans bspnode) 
    { 
    (frontpiece, backpiece) = split(triangle, bspnode) 

    handle = beginthread(insert(backpiece, bspnode.front)) 
    insert(frontpiece, bspnode.back) 
    if(handle) 
    { 
     waitforthread(handle) 
    } 
    else 
    { 
     insert(backpiece, bspnode.front) 
    } 
    } 
    .... 
} 

这种新方法试图创建一个线程来完成并行操作,但如果线程不能创建应该不会失败(这将简单地恢复到原来的算法)。

这是一个完善的编程习惯,还是我使用线程不当?我一直无法找到关于这种技术的任何文献。我喜欢它倾向于使用我的CPU到最完整的(2个内核),并且理论上可以扩展到任何数量的可用处理器。我不喜欢它在CPU和内存上可能会非常浪费。如果处理的某些部分上的东西外等待

回答

11

线程是伟大的(用户输入,I/O,其他的一些处理) - 这是等待可以继续等待线程,而线程未在等待伪造先。

然而,对于处理密集型任务,比处理器的多个线程实际创建的开销。看起来你的线程正在完成所有“CPU工作”,所以我坚持每个内核都有一个线程 - 测试以找到最佳数目。

创建的最大开销是从上下文切换(冻结一个线程并加载下一个执行上下文),以及线程使用不同内存执行任务时缓存未命中(如果您的线程可以有效使用CPU缓存)。

+1

哦,他是RHYMES! :) HAHAH NICE! – Kiril 2008-12-01 17:05:30

2

你最好的选择是创建一个线程池,然后用它“透明”添加节点。

例如,创建程序启动2个线程,让他们等待一个信号量或事件。当您添加节点时,您将数据弹出到队列中,然后触发信号量。这会唤醒将数据从队列中弹出并执行处理的线程之一。 (确保对队列的访问是线程安全的 - 与关键部分完全同步是最好的)。

由于在将数据复制到队列中并运行额外的线程时,应用程序的整体性能较慢,但如果您曾经在单个内核上运行,则现在将运行在2.它工作正常如果线程处理非常昂贵,那么最好。

0

当然,例如,快速排序可以编程多线程很容易,并获得多核心系统,并在非多线程一些小的性能损失,一些大的性能提升。请记住,现在你需要两次额外的开销 - 一次是堆栈节省递归,一次是在线程上,所以如果你做了大量的递归,那么它可能比非多线程方法更快地压倒一个系统。