本文描述了算法:Thread Scheduling for Multiprogrammed Multiprocessors。简而言之,计算在进程中被分解,并且每个进程都有一个线程的deque来完成这项工作。进程可以将(弹出)线程推送到(来自)其双端队列的底部,并且其他进程可以通过从顶部弹出线程来从中窃取。因此,可以通过推动操作来动态地创建工作。算法如下。
我的问题是popTop()工作窃取功能。我不认为它适用于所有情况。例如,假设进程A的队列Q和进程B试图从Q窃取工作,调用popTop()。假设此时B在popTop()的第2行和localBot = X之后被抢占。如果A运行并且popBottom()直到Q< = X的底部,当B恢复运行时,它将获得一个已经由A处理过的线程。
我的想法是否正确?我需要验证它,因为我将实现它以在CUDA程序中进行工作平衡。
答案 0 :(得分:2)
代码使用cas()(比较和交换)来尝试阻止你所描述的事情。如果popTop()在第2行之后停止,则在读入age和bot之后它会停止。如果popBottom()然后运行并返回一个线程,它将在年龄内增加字段,并使用cas()将增量版本写回内存。现在当B恢复并调用cas()时,cas()指令发现B为age提供的值与内存中的值不匹配(这意味着对cas()的这种调用不会修改内存)。所以B发现(oldAge == newAge)并返回ABORT。在这种情况下,你通常会再试一次,希望下次能有更好的运气。这篇文章似乎是说对yield()的调用对于你获得不错的运气是必要的,但无论如何popTop()不应该返回别人抓过的线程。
@ {3}}上有关于cas()的维基百科文章。
我会使用比串行代码高一级难度的锁定并行代码,并且锁定并行代码比锁定并行代码高一级难度。我不会写无锁并行代码,除非我确定我需要性能,并且没有现有的已知可靠代码可以重用。在我对其进行详尽测试之前,我不会相信这些代码,如果可能的话,我实际上更愿意进行模型检查。