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.rhkb.cn/news/213039.html

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

相关文章

AR + 通信,虚实结合让工作协同从线上到「现场」

在数字经济无所不在的当下&#xff0c;千行百业都与数智化办公接轨并因其实现转型升级。关注【融云 RongCloud】&#xff0c;了解协同办公平台更多干货。 升级的背后&#xff0c;是利用技术把工作用更自然的方式连接起来&#xff0c;让整个工作流协同更顺、体验更好。 而其中…

应用架构——集群、分布式、微服务的概念及异同

一、什么是集群&#xff1f; 集群是指将多台服务器集中在一起&#xff0c; 每台服务器都实现相同的业务&#xff0c;做相同的事&#xff1b;但是每台服务器并不是缺 一不可&#xff0c;存在的主要作用是缓解并发能力和单点故障转移问题。 集群主要具有以下特征&#xff1a; …

042:el-table表格表头自定义高度(亲测好用)

第042个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

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

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

【iOS】网络请求GET与POST

【iOS】网络请求GET与POST 前沿一. GET与POST的共同点二. GET与POST的不同点三. 实现方式总结 前沿 HTTP定义了与服务器交互的不同方法&#xff0c;最基本的方法有4种&#xff0c;分别是GET&#xff0c;POST&#xff0c;PUT&#xff0c;DELETE。URL全称是资源描述符&#xff0…

护眼灯有效果吗?考研必备护眼台灯推荐

据统计&#xff0c;中国人口的近视率约为10%至20%。 国家卫健委发布的中国首份眼健康白皮书显示&#xff0c;我国小学生近视率为47.2%&#xff0c;初中生近视率为75.8%&#xff0c;大学生近视率超过90%。据世界卫生组织统计数据显示&#xff0c;目前全球约有14亿近视人口&#…

【C语言】深入理解C语言中的数学运算和类型转换

文章目录 引言取负运算的奥秘源码探索分析与解读 浮点数运算的精细差异源码分析精度损失与隐式类型转换 精度和除零运算探究float类型和double类型的精度各是多少&#xff08;即十进制有效位的位数&#xff09;&#xff1f;在你的机器上&#xff0c;“负数开方”是如何处理的&a…

LeetCode题:174. 地下城游戏

目录 一、题目要求 二、解题思路 &#xff08;1&#xff09;状态表示 &#xff08;2&#xff09;状态转移方程 &#xff08;3&#xff09;初始化dp表 &#xff08;4&#xff09;填表顺序 &#xff08;5&#xff09;返回值 三、代码 一、题目要求 174. 地下城游戏 恶魔们…

关于什么是 JVM

关于什么是 JVM&#xff0c;看看普通⼈和⾼⼿的回答。 普通人 JVM 就是 Java 虚拟机&#xff0c;是⽤来运⾏我们平时所写的 Java 代码的。优点是它会 ⾃动进⾏内存管理和垃圾回收&#xff0c;缺点是⼀旦发⽣问题&#xff0c;要是不了解 JVM 的运⾏ 机制&#xff0c; 就很难…

C#中GDI+绘图应用(柱形图、折线图和饼形图)

目录 一、柱形图 1.示例源码 2.生成效果 二、折线图 1.示例源码 2.生成效果 三、饼形图 1.示例源码 2.生成效果 GDI绘制的一些常用的图形&#xff0c;其中包括柱形图、折线图和饼形图。 一、柱形图 柱形图也称为条形图&#xff0c;是程序开发中比较常用的一种图表技术…

2024年网络安全行业前景和技术自学

很多人不知道网络安全发展前景好吗&#xff1f;学习网络安全能做什么&#xff1f;今天为大家解答下 先说结论&#xff0c;网络安全的前景必然是超级好的 作为一个有丰富Web安全攻防、渗透领域老工程师&#xff0c;之前也写了不少网络安全技术相关的文章&#xff0c;不少读者朋…

vuepress-----19、自动生成侧边栏

自动生成侧边栏插件 https://github.com/shanyuhai123/vuepress-plugin-auto-sidebar https://shanyuhai123.github.io/vuepress-plugin-auto-sidebar/ 安装 npm i vuepress-plugin-auto-sidebar -Dmodule.exports {plugins: [["vuepress-plugin-auto-sidebar",…

【抽象策略模式】实践

前言 刚果商城&#xff0c;用户登录 Or 注册 发送邮箱验证码场景&#xff0c;使用抽象策略模式实现 什么是抽象策略模式 抽象策略模式是一种行为型设计模式&#xff0c;它允许定义一系列算法&#xff0c;将每个算法封装起来&#xff0c;并使它们可以互相替换。这使得客户端代码…

牛客在线编程(SQL大厂面试真题)

1.各个视频的平均完播率_牛客题霸_牛客网 ROP TABLE IF EXISTS tb_user_video_log, tb_video_info; CREATE TABLE tb_user_video_log (id INT PRIMARY KEY AUTO_INCREMENT COMMENT 自增ID,uid INT NOT NULL COMMENT 用户ID,video_id INT NOT NULL COMMENT 视频ID,start_time d…

NSS [NSSCTF 2022 Spring Recruit]babyphp

NSS [NSSCTF 2022 Spring Recruit]babyphp 考点&#xff1a;PHP特性 开局源码直接裸奔 <?php highlight_file(__FILE__); include_once(flag.php);if(isset($_POST[a])&&!preg_match(/[0-9]/,$_POST[a])&&intval($_POST[a])){if(isset($_POST[b1])&&…

【K8s】Kubernetes CRD 介绍(控制器)

文章目录 CRD 概述1. 操作CRD1.1 创建 CRD1.2 操作 CRD 2. 其他笔记2.1 Kubectl 发现机制2.2 校验 CR2.3 简称和属性 3. 架构设计3.1 控制器概览 参考 CRD 概述 CR&#xff08;Custom Resource&#xff09;其实就是在 Kubernetes 中定义一个自己的资源类型&#xff0c;是一个具…

VMware上不去网

VMwarw上不去网了&#xff0c;之前还好好的&#xff0c;这又是碰了哪里。ifconfig提示no device. 又开始折腾&#xff0c;一顿猛如虎的操作。 先把网络各种禁用&#xff0c;再开启。未解决。 最后的解决了的方案&#xff0c;重新设置了虚拟机的网络。 网络1设置为桥接 网络…

AIGC创作系统ChatGPT网站源码,Midjourney绘画,GPT联网提问/即将支持TSS语音对话功能

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

数据库的索引

索引的特点 1&#xff09;加快查询的速度 2&#xff09;索引自身是一种数据结构&#xff0c;也要占用存储空间 3&#xff09;当我们需要进行增删改的时候&#xff0c;也要对索引进行更新&#xff08;也需要额外的空间开销&#xff09; sql操作 查看索引 show index from …

node后端接口无法插入数据为emoji的表情的问题

原因 emoji的表情一般是这样的\xF0\x9F\x98\x80或者是\xF0\x9F\x98 &#xff0c;事实上 一般数据库的utf8的编码类型都是能保存\xF0\x9F\x98 但是不能保存\xF0\x9F\x98\x80这种样的emoji&#xff0c;要将数据库编码格式为utf8mb4 也就是utf8的超集 另外&#xff0c;除了 数据库…