cuda lib 线程安全的要义

1, 概述

cuda lib 线程安全的几个多线程的情景:

单卡多线程;

多卡多线程-每卡单线程;

多卡多线程-每卡多线程;

需要考虑的问题:


每个 cublasHandle_t 只能有一个stream么?
每个cusolverHandle_t 只能有一个 stream么?
每个cusolverHandle_t只能有要给cublasHandle_t么?
多个线程同时跑在多个或一个gpu上,需要使用多个stream么?都是NULL 默认stream的话,不会影响效率吧?

2, 多线程示例

从如下代码思考开去,这个多线程场景是使用了openmp自动划分任务,也可以使用pthread来七分任务,这里对这个示例进行了注释:

https://github.com/NVIDIA/cuda-samples/blob/v11.4/Samples/cudaOpenMP/cudaOpenMP.cu

/** Multi-GPU sample using OpenMP for threading on the CPU side* needs a compiler that supports OpenMP 2.0*/
//使用openmp时包含其头文件
#include <omp.h>
#include <stdio.h>  // stdio functions are used since C++ streams aren't necessarily thread safe
//#include <helper_cuda.h>#define checkCudaErrors(val)  valusing namespace std;// a simple kernel that simply increments each array element by b
__global__ void kernelAddConstant(int *g_a, const int b)
{int idx = blockIdx.x * blockDim.x + threadIdx.x;g_a[idx] += b;
}// a predicate that checks whether each array element is set to its index plus b
int correctResult(int *data, const int n, const int b)
{for (int i = 0; i < n; i++)if (data[i] != i + b)return 0;return 1;
}int main(int argc, char *argv[])
{int num_gpus = 0;   // number of CUDA GPUsprintf("%s Starting...\n\n", argv[0]);/// determine the number of CUDA capable GPUs//cudaGetDeviceCount(&num_gpus);if (num_gpus < 1){printf("no CUDA capable devices were detected\n");return 1;}/// display CPU and GPU configuration//printf("number of host CPUs:\t%d\n", omp_get_num_procs());printf("number of CUDA devices:\t%d\n", num_gpus);for (int i = 0; i < num_gpus; i++){cudaDeviceProp dprop;cudaGetDeviceProperties(&dprop, i);printf("   %d: %s\n", i, dprop.name);}printf("---------------------------\n");/// initialize data//unsigned int n = num_gpus * 8192;unsigned int nbytes = n * sizeof(int);// nbytes = num_gpus * [8192*sizeof(int)]printf("nbytes=%u\n", nbytes);int *a = 0;     // pointer to data on the CPUint b = 3;      // value by which the array is incrementeda = (int *)malloc(nbytes);if (0 == a){printf("couldn't allocate CPU memory\n");return 1;}
//这里如果使用 #pragma omp parallel for 的话,会不会影响下面的线程数?for (unsigned int i = 0; i < n; i++)a[i] = i;// run as many CPU threads as there are CUDA devices//   each CPU thread controls a different device, processing its//   portion of the data.  It's possible to use more CPU threads//   than there are CUDA devices, in which case several CPU//   threads will be allocating resources and launching kernels//   on the same device.  For example, try omp_set_num_threads(2*num_gpus);//   Recall that all variables declared inside an "omp parallel" scope are//   local to each CPU thread//// 通过获知GPU的数量来设定下面参与工作的线程数量omp_set_num_threads(num_gpus);  // create as many CPU threads as there are CUDA devices//omp_set_num_threads(2*num_gpus);// create twice as many CPU threads as there are CUDA devices//自动创建 num_gpus 个线程#pragma omp parallel{//每个线程获得自己的线程号,从0开始计数unsigned int cpu_thread_id = omp_get_thread_num();//获取 openmp 自动创建的总的线程数unsigned int num_cpu_threads = omp_get_num_threads();printf("cpu_thread_id=%u   num_cpu_threads=%u\n", cpu_thread_id, num_cpu_threads);// set and check the CUDA device for this CPU threadint gpu_id = -1;//两个或以上的线程,可以同时使用同一个 gpu 设备;cudaSetDevice(id) 会使得本线程锁定这个 id-th gpu 设备,接下来发生的cudaXXX,都是在这个gpu上发生的。checkCudaErrors(cudaSetDevice(cpu_thread_id % num_gpus));   // "% num_gpus" allows more CPU threads than GPU devicescheckCudaErrors(cudaGetDevice(&gpu_id));//这个函数仅仅返回本线程锁定的gpu的id。printf("CPU thread %d (of %d) uses CUDA device %d, set id=%d, get id = %d\n", cpu_thread_id, num_cpu_threads, gpu_id, cpu_thread_id%num_gpus, gpu_id);int *d_a = 0;   // pointer to memory on the device associated with this CPU thread//下面找到本线程需要处理的数据起始地址int *sub_a = a + cpu_thread_id * n / num_cpu_threads;   // pointer to this CPU thread's portion of dataunsigned int nbytes_per_kernel = nbytes / num_cpu_threads;//其中的 nbytes = num_gpus * [8192*sizeof(int)], 是整除关系;得到每个线程需要分配的显存字节数dim3 gpu_threads(128);  // 128 threads per blockdim3 gpu_blocks(n / (gpu_threads.x * num_cpu_threads));// n = num_gpus * 8192;   其中 8192 是128的整数倍, num_cpu_threads 是 num_gpus 的小小的整数倍; // 这样每个block含128个线程; 每个线程需要几个block呢 = n/(gpu_threads.x * num_cpu_threads)checkCudaErrors(cudaMalloc((void **)&d_a, nbytes_per_kernel));//在本线程所setDevice的gpu上cudaMalloc显存空间;checkCudaErrors(cudaMemset(d_a, 0, nbytes_per_kernel));//将分的的空间刷0// 将本线程需要处理的数据块拷贝的本线程所cudaMalloc的显存中;checkCudaErrors(cudaMemcpy(d_a, sub_a, nbytes_per_kernel, cudaMemcpyHostToDevice));//本线程启动kernel,处理自己的显存的数据;kernelAddConstant<<<gpu_blocks, gpu_threads>>>(d_a, b);// 本线程将处理好的数据拷贝到本线程负责的系统内存块中checkCudaErrors(cudaMemcpy(sub_a, d_a, nbytes_per_kernel, cudaMemcpyDeviceToHost));//释放显存checkCudaErrors(cudaFree(d_a));}printf("---------------------------\n");if (cudaSuccess != cudaGetLastError())printf("%s\n", cudaGetErrorString(cudaGetLastError()));// check the result//对计算结果进行对比bool bResult = correctResult(a, n, b);if (a)free(a); // free CPU memoryexit(bResult ? EXIT_SUCCESS : EXIT_FAILURE);
}


运行效果:


要保证cuda lib的线程安全,首先确定cuda driver cuda runtime 都是线程安全的,这个其实是没有问题的,也就是说多个线程多块显卡同时运行的场景是不会引发cuda runtime的线程安全问题的,这点可以放心;

3, 多线程安全分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/208128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3.5安装教程及环境配置,python3.7.2安装与配置

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python3.5安装教程及环境配置&#xff0c;python3.7.2安装与配置&#xff0c;现在让我们一起来看看吧&#xff01; python 从爬虫开始&#xff08;一&#xff09; Python 简介 首先简介一下Python和爬虫的关系与概念&am…

Spring Cloud Alibaba实践 --Sentinel

sentinel简介 Sentinel的官方标题是&#xff1a;分布式系统的流量防卫兵。从名字上来看&#xff0c;很容易就能猜到它是用来作服务稳定性保障的。对于服务稳定性保障组件&#xff0c;如果熟悉Spring Cloud的用户&#xff0c;第一反应应该就是Hystrix。但是比较可惜的是Netflix…

三防平板|手持终端PDA|8寸/10寸工业三防平板电脑主板方案定制

近年来&#xff0c;随着科技的快速发展&#xff0c;三防平板成为了各行各业中不可或缺的工具。三防平板采用IP67级别的防护设计&#xff0c;通过了多项测试标准&#xff0c;如国标和美标&#xff0c;具备防水、防摔、防尘、防撞、防震、防跌落以及防盐雾等多重防护功能。因此&a…

JavaScript 简单理解原型和创建实例时 new 操作符的执行操作

function Person(){// 构造函数// 当函数创建&#xff0c;prototype 属性指向一个原型对象时&#xff0c;在默认情况下&#xff0c;// 这个原型对象将会获得一个 constructor 属性&#xff0c;这个属性是一个指针&#xff0c;指向 prototype 所在的函数对象。 } // 为原型对象添…

HarmonyOS应用开发工具DevEco Studio安装与使用

语雀知识库地址&#xff1a;语雀HarmonyOS知识库 飞书知识库地址&#xff1a;飞书HarmonyOS知识库 知识库内容逐步完善中… 工欲善其事必先利其器&#xff0c;要编写HarmonyOS应用就需要用到官方提供的IDE工具来编写相应的代码。 在鸿蒙开发者官网&#xff0c;其提供了官方的开…

高效的多维空间点索引算法——GeoHash

一、Geohash 算法简介 GeoHash是空间索引的一种方式&#xff0c;其基本原理是将地球理解为一个二维平面&#xff0c;通过把二维的空间经纬度数据编码为一个字符串&#xff0c;可以把平面递归分解成更小的子块&#xff0c;每个子块在一定经纬度范围内拥有相同的编码。以GeoHash方…

springboot 极简案例

安装idea File -> New Project 选择依赖 创建controller文件 输入controller类名 输入代码 运行项目 访问 localhost:8080/hello/boot package com.example.demo;import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.…

数据库对象介绍与实践:视图、函数、存储过程、触发器和物化视图

文章目录 一、视图&#xff08;View&#xff09;1、概念2、基本操作1&#xff09;创建视图2&#xff09;修改视图3&#xff09;删除视图4&#xff09;使用视图 3、使用场景4、实践 二、函数&#xff08;Function&#xff09;1、概念2、基本操作1&#xff09;创建函数2&#xff…

粤能环保亮相迪拜COP28,智能技术铸就运河城市可持续未来

在全球应对气候变化的重要会议——迪拜COP28大会上&#xff0c;运河城市面临的独特环境挑战引起了广泛关注。随着城市化进程的加快&#xff0c;运河城市在处理固体废物、减少温室气体排放以及维持水资源安全方面面临着严峻考验。智能垃圾分类作为应对这些挑战的有效途径&#x…

一些系统日常运维命令和语句

一、前言 记录一些日常系统运维的命令和语句 二、linux命令与语句 1、linux查看各目录使用磁盘情况 du -h /home home为目录 du -h /home 2.查看内存使用情况 free -h 3、查看进程和CPU使用情况 top top 三、数据库语句 1、统计mysql数据库表数量 SELECT COUNT(*) A…

被动副业机赚钱项目教程,Docker一键安装教程

被动副业机赚钱项目教程&#xff0c;Docker一键安装教程 Docker一键运行 软件下载 视频教程 /opt/wxedge_storage 路径换成你设备里面的路径即可&#xff0c;其余参数不用变&#xff0c; 镜像名为onething1/wxedge 更多安装说明&#xff0c;可参考官方文档&#xff1a;容器魔…

【算法每日一练]-结构优化(保姆级教程 篇4 树状数组,线段树,分块模板篇)

目录 分块 分块算法步骤&#xff1a; 树状数组 树状数组步骤&#xff1a; 线段树点更新 点更新步骤&#xff1a; 线段树区间更新 区间更新步骤&#xff1a; 不同于倍增和前缀和与差分序列。 前缀和处理不更新的区间和 差分处理离线的区间更新问题 倍增处理离线的区间…

维普论文查重率高【详细说明】

大家好&#xff0c;今天来聊聊维普论文查重率高&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff1a; 维普论文查重率高&#xff1a;原因分析与降重技巧 背景介绍 在学术领域&#xff0c;论文的重复率是衡量其…

老电脑重置后能连上WIFI但是打开360网页老是提示该网址不是私密连接

看了一下可以忽略这次提示&#xff0c;能够上网&#xff0c;但是每次打开新网页都会有“该网址不是私密连接”提示&#xff0c;这个提示非常大&#xff0c;严重影响上网。 强行下载了谷歌浏览器并打开后&#xff0c;提示“您的时钟慢了”&#xff0c;然后看了一下电脑右下角日期…

CLion手把手教你创建Windows项目

作为一个Jetbrains迷的我&#xff0c;下载了Jetbrains全家桶&#xff0c;我就想用CLion 编写 Windows 项目 前提&#xff1a;必须安装 Visual Studio 2022 New Project 选择 C Executable&#xff0c;取好项目名&#xff0c; 点击 Create 在 CMakeList.txt 中添加以下内容&…

系列八、SpringBoot中自定义SpringMVC配置

一、概述 作为Spring家族的明星产品&#xff0c;SpringBoot极大地简化了程序员的日常开发&#xff0c;提高了开发效率。我们很容易得借助于SpringBoot就可以快速开发业务代码。一般情况下&#xff0c;公司的日常开发都是基于web服务的&#xff0c;我们在使用idea等工具初始化一…

Zabbix补充

Zabbix的自动发现机制&#xff1a; Zabbix客户端主动和服务端联系&#xff0c;将自己的地址和端口发送服务端&#xff0c;来实现自动添加主机 客户端是自动的一方 缺点&#xff1a;自定义的网段的主机数量太多&#xff0c;登记耗时会很久&#xff0c;而且这个自动发现机制不是…

Ubuntu 22.04源码安装yasm 1.3.0

sudo lsb_release -r看到操作系统的版本是22.04&#xff0c;sudo uname -r可以看到内核版本是5.15.0-86-generic&#xff0c;sudo gcc --version可以看到版本是11.2.0&#xff0c;sudo make --version可以看到版本是GNU Make 4.3。 下载yasm http://yasm.tortall.net/Downlo…

扁平的MutableList元素每隔若干元素一组装入新MutableList,Kotlin

扁平的MutableList元素每隔若干元素一组装入新MutableList&#xff0c;Kotlin fun main(args: Array<String>) {val array arrayOf("a", "b", "c", "d", "e", "f", "g", "h", "i…

Numpy数组的重塑,转置与切片 (第6讲)

Numpy数组的重塑,转置与切片 (第6讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…