如何一个__global__函数返回一个值或BREAK像C / C ++ [英] how can a __global__ function RETURN a value or BREAK out like C/C++ does

查看:200
本文介绍了如何一个__global__函数返回一个值或BREAK像C / C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我一直在做比较CUDA上的作业的字符串,我想知道__global__函数如何在返回一个值,当它找到我正在寻找的确切字符串。

Recently I've been doing string comparing jobs on CUDA, and i wonder how can a __global__ function return a value when it finds the exact string that I'm looking for.

我的意思是,我需要__global__函数,其中包含大量的线程来查找一个大的字符串池同时的一个特定的字符串,我希望一旦确切的字符串被捕获,__global__函数可以停止所有线程并返回到主函数,并告诉我他做了!

I mean, i need the __global__ function which contains a great amount of threads to find a certain string among a big big string-pool simultaneously, and i hope that once the exact string is caught, the __global__ function can stop all the threads and return back to the main function, and tells me "he did it"!

我使用CUDA C.如何可能实现这个? p>

I'm using CUDA C. How can I possibly achieve this?

推荐答案

对于一个线程,CUDA(或NVIDIA GPU)没有办法中断所有正在运行的线程的执行。

There is no way in CUDA (or on NVIDIA GPUs) for one thread to interrupt execution of all running threads. You can't have immediate exit of the kernel as soon as a result is found, it's just not possible today.

但是你可以让所有的线程退出作为一个结果,你不能立即退出内核。尽快在一个线程找到结果后。这是一个如何做的模型。

But you can have all threads exit as soon as possible after one thread finds a result. Here's a model of how you would do that.

__global___ void kernel(volatile bool *found, ...) 
{
    while (!(*found) && workLeftToDo()) {

       bool iFoundIt = do_some_work(...); // see notes below

       if (iFoundIt) *found = true;
    }
}

有关这方面的注意事项。

Some notes on this.


  1. 注意使用 volatile 。这个很重要。

  2. 确保您初始化找到—必须是 false

  3. 如何实现 do_some_work 重要事项。如果它是太多的工作(或太多的变量),那么在发现结果之后退出的延迟将是长的(或变量)。如果它太少的工作,那么你的线程将花大部分时间检查找到,而不是做有用的工作。

  4. do_some_work 也负责分配任务(即计算/递增索引),以及如何处理这些问题。 li>
  5. 如果您启动的块的数量远大于当前GPU上的内核的最大占用量,并且在第一个运行的wave的线程块中找不到匹配,则这个内核(和下面的一个)可能会死锁。如果在第一个wave中找到匹配,则稍后的块将仅在 found == true 之后运行,这意味着它们将启动,然后立即退出。解决方案是启动尽可能多的块,同时可以驻留(也称为最大启动),并相应地更新您的任务分配。

  6. 如果任务数量相对较少,您可以使用替换,而 c $ c>并运行足够的线程来覆盖任务数量。

  7. workLeftToDo()是问题特定的,但是当没有剩余的工作要做时,它会返回false,以便在找不到匹配的情况下我们不会死锁。

  1. Note the use of volatile. This is important.
  2. Make sure you initialize found—which must be a device pointer—to false before launching the kernel!
  3. Threads will not exit instantly when another thread updates found. They will exit only the next time they return to the top of the while loop.
  4. How you implement do_some_work matters. If it is too much work (or too variable), then the delay to exit after a result is found will be long (or variable). If it is too little work, then your threads will be spending most of their time checking found rather than doing useful work.
  5. do_some_work is also responsible for allocating tasks (i.e. computing/incrementing indices), and how you do that is problem specific.
  6. If the number of blocks you launch is much larger than the maximum occupancy of the kernel on the present GPU, and a match is not found in the first running "wave" of thread blocks, then this kernel (and the one below) can deadlock. If a match is found in the first wave, then later blocks will only run after found == true, which means they will launch, then exit immediately. The solution is to launch only as many blocks as can be resident simultaneously (aka "maximal launch"), and update your task allocation accordingly.
  7. If the number of tasks is relatively small, you can replace the while with an if and run just enough threads to cover the number of tasks. Then there is no chance for deadlock (but the first part of the previous point applies).
  8. workLeftToDo() is problem-specific, but it would return false when there is no work left to do, so that we don't deadlock in the case that no match is found.

现在,以上可能会导致过多的分区驻留(所有线程都在同一内存上),特别是在没有L1缓存的老式架构上。因此,您可能希望使用每个块的共享状态编写稍微更复杂的版本。

Now, the above may result in excessive partition camping (all threads banging on the same memory), especially on older architectures without L1 cache. So you might want to write a slightly more complicated version, using a shared status per block.

__global___ void kernel(volatile bool *found, ...) 
{
    volatile __shared__ bool someoneFoundIt;

    // initialize shared status
    if (threadIdx.x == 0) someoneFoundIt = *found;
    __syncthreads();

    while(!someoneFoundIt && workLeftToDo()) {

       bool iFoundIt = do_some_work(...); 

       // if I found it, tell everyone they can exit
       if (iFoundIt) { someoneFoundIt = true; *found = true; }

       // if someone in another block found it, tell 
       // everyone in my block they can exit
       if (threadIdx.x == 0 && *found) someoneFoundIt = true;

       __syncthreads();
    }
}

这样,每个块一个线程轮询全局变量,并且只有找到匹配的线程写入它,因此全局内存流量被最小化。

This way, one thread per block polls the global variable, and only threads that find a match ever write to it, so global memory traffic is minimized.

Aside:__global__函数是无效的,因为很难定义如何返回值从1000s的线程到单个CPU线程。对于用户来说,设计一个符合他的目的的设备或零拷贝存储器中的返回数组是很容易的,但很难创建一个通用的机制。

Aside: __global__ functions are void because it's difficult to define how to return values from 1000s of threads into a single CPU thread. It is trivial for the user to contrive a return array in device or zero-copy memory which suits his purpose, but difficult to make a generic mechanism.

免责声明:使用浏览器编写的代码,未经测试,未验证。

Disclaimer: Code written in browser, untested, unverified.

这篇关于如何一个__global__函数返回一个值或BREAK像C / C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆