循环创建多线程时保证参数的有效性

2024-04-11 00:32

本文主要是介绍循环创建多线程时保证参数的有效性,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

循环创建多线程时保证参数的有效性    
当我们需要在一个循环中传递参数时,使用使用函数的方法一般都是:    
for(int   I=0;I <100;I++)
{                  
fun(I);           //使用函数传递i   
}    


每一个循环都会等待fun(I);函数执行完后再进行下一个循环。    
但是当我们需要这个循环中创建线程,并将I的参数传递给线程时,如依然使用以上方法,会造成什么情况呢?    
DWORD   WINAPI   ThreadFun(LPVOID   lpParam)
{                             //线程函数                  
Int   *I   =   (int   *)lpParam;                  Return   0;   
}        


int   I;    
for(I=0;I <100;I++)
{    
DWORD   dwThreadId;            HANDLE   hThread;             
hThread   =   CreateThread(NULL,0,ThreadFunc,&I,0,&dwThreadId);  
}    


好了,到这里我们就可以发现,在循环中,我们创建线程并传递的参数是I=1后,主程序有可能在执到下一次循环时,第一次的ThreadFun函数仍未执行,而此时的I已经等2了,如果ThreadFun再来调用               
Int   *I   =   (int   *)lpParam;语句时,显然不是我们想要的结果。        
解决此问题的一种方法,便是可以使用静态数组来保存所要传递的参数。
如下: 
   
int   I;    
static   int   nPara[100];           //此句需定义为全局    
for(I=0;I <100;I++)
{    
DWORD   dwThreadId;    
HANDLE   hThread;    
NPara[I]=I;                 //保存参数          
hThread   =   CreateThread(NULL,0,ThreadFunc,&nPara[I],0,&dwThreadId); 
}    
此时,所有参数均保存在nPara数组中,刚才的问题是解决了。


接下来又有了新的问题,让我们一起来看看吧:  
  1、如果需要创建的线程不止100,而是非常的大,而且我们也并不知道会有多少次循环的时侯。  
  2、如果我们需要传递的参数不单单只是一个int型的I,而是一个类。那么我们声明的时侯


(假设线程数量最大为65535)则:    
static   CMYClass   myClass[65535];   


编译之后,得到的文件将会堆上一大堆的垃圾。相信任何一位程序都不想看到自己的程序上面堆了一堆垃圾在上面吧。 那么,还有没有更好的办法解决呢。答案是一定的,这里,我就讲一下我自己常用的方法:动态创建对像传递参数。
  
一提到动态创建,我们自然会想到new   与   delete   ,
对了,我想说的也正是他们的使用。    
假设参数类型为:    
typedef   struct   _PARA
{  
int   I;            
DWORD   dwNumber;            
HWND   hOther;    
}Para;  


使用new在堆栈中申请一遍空间,在使用完后必需使用delete将其释放。    


int   I;    
for(I=0;I <100;I++)
{    
DWORD   dwThreadId;    
HANDLE   hThread;     
Para   *myPara   =   new   Para;  
MyPara-> I   =   I;   MyPara-> dwNumber   =   0   ;//自定   
MyPara   -> hOther   =   GetSafeHWnd();//当前窗体句柄           
hThread   =   CreateThread(NULL,0,ThreadFunc,myPara,0,&dwThreadId); //线程函数  
}           


DWORD   WINAPI   ThreadFun(LPVOID   lpParam)
{                             
//线程函数                  
Para   *myPara   =   (Para   *)lpParam;                  //执行其他功能
delete   []   myPara;                                 //释放                 
Return   0;   
}  
  
这样的话,也就不怕传递的参数多少与线程的数量太大了。另外如有需要的话可以加上一个线程计数器,保证当前线程的最大数量。   
通常情况,我比较喜欢把线程处理放在一个类中处理,在主程序中尽量不与线程打交道。        


在循环中使用new 可以保证每次申请到的内存的地址不会是同一个(即不会重复),从而传递给每个线程的参数也互不冲突,互不干扰,相互独立,在线程内部使用完参数后,根据接收的地址,使用delete释放申请的内存块。 
用结构,然后将结构的指针传给CreateThread()的参数lpParameter。需要  注意:
结构应该是“静态的”或是“全局的”或者是“动态分配的”。
如果使用局部  变量,有可能在线程调用这个结构时,结构已经不在栈中了。  
struct   StructA  
{           
int   n1,   n2,   n3,   n4,   n5;  
};    


DWORD   WINAPI   ThreadFun(LPVOID*   param)  
{
StructA*   pa   =   (StructA*)param;          //这儿就可以访问结构中的变量了         
//......           return   1;  
}    
void   TestFunc()  
{           
DWORD   dwID;            
//下面的写法不对          
StructA   a;  
        CreateThread(NULL,   0,   ThreadFun,   &a,   0,   &dwID);            
//下面的写法是对的          
static   StructA   a;           
CreateThread(NULL,   0,   ThreadFun,   &a,   0,   &dwID);  

这篇关于循环创建多线程时保证参数的有效性的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

idea+spring boot创建项目的搭建全过程

《idea+springboot创建项目的搭建全过程》SpringBoot是Spring社区发布的一个开源项目,旨在帮助开发者快速并且更简单的构建项目,:本文主要介绍idea+springb... 目录一.idea四种搭建方式1.Javaidea命名规范2JavaWebTomcat的安装一.明确tomcat

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

Git打标签从本地创建到远端推送的详细流程

《Git打标签从本地创建到远端推送的详细流程》在软件开发中,Git标签(Tag)是为发布版本、标记里程碑量身定制的“快照锚点”,它能永久记录项目历史中的关键节点,然而,仅创建本地标签往往不够,如何将其... 目录一、标签的两种“形态”二、本地创建与查看1. 打附注标http://www.chinasem.cn

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty