发布时间:2025-12-09 14:06:40 浏览次数:5
CreateThread是一种微软在Windows API中提供了建立新的线程的函数,该函数在主线程的基础上创建一个新线程。线程终止运行后,线程对象仍然在系统中,必须通过CloseHandle函数来关闭该线程对象。
需要调用到CRT库时,不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,而应该用_beginthread来创建线程,_endthread来销毁线程。因为没有对子线程为CRT库分配堆,会导致低内存错误而崩溃。
CreateThread 不会判断lpStartAddr是数据还是代码,甚至不会判断是否有足够的访问权限。lpStartAddr可以未必是个函数,也可以是类成员,只要将函数指针强制转换,并且不产生栈溢出和没有访问权限的问题就以及类如未定义的指令之类的错误可以顺利执行线程。创建类成员函数的对象时,this指针是调用CreateThread时所处的类对象的指针。在类对象外调用,其this指针将是未知的。
什么是线程
1、在Windows平台上,最终可以利用CPU执行代码的最小尸体就是线程
2、首先从内核角度看,线程是一个内核对象,系统用它来村塾一些关于线程统计信息(比如时间)
3、从编程角度来看,线程是一堆寄存器状态以及线程栈的一个结构体对象,本质上可以理解为一个函数调用其(
寄存器状态用与控制CPU执行,栈用于存储局部变量和函数调用参数及函数返回地址)
4、最后需要知道的就是线程还可以带有几个队列(简单的理解为异步函数调用队列):
消息队列(GUI线程系统内部会创建)
APC队列(调用APC函数时会创建)
(注意:这些队列在线程创建时比并不存在)
5、线程就是执行体
什么时候不使用线程
1、当一个算法是严格穿行化的时候,也就是计算的每一步都严重以来前一个操作步骤的结果的时候
2、当有多个功能任务也具有比较严格的先后逻辑关系的时候,不宜采用多线程
3、还有一个特殊情况,比如一个服务器需要处理成千上万个客户端链接,并处理不同的请求的时候,这种
情况下应当优先考虑线程池,而不是简单的多线程。
默认的线程函数必须具有如下原型
DWORD WINAPI ThreadProc(LPVOID LpParameter);
调用API:CreateThread可以创建一个新进程HANDLEWINAPICreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,
SIZE_TdwStackSize,
LPTHREAD_START_ROUTINElpStartAddress,
LPVOIDlpParameter,
DWORDdwCreationFlags,
LPDWORDlpThreadId
);
其中安全属性参数指定的是创建新进程内核对象的安全属性,不是线程访问字符串(Token)的属性
dwStackSize用于指定线程初始时的栈大小,通常传入0即可,此时系统会使用一个合适的大小
lpStartAddress就是新进程入口函数的地址
lpParameter就是传入线程入口的参数,这个参数完全由调用者使用,系统只是简单的将这个参数
传递给线程函数,并不做别的任何处理
dwCreationFlags指出创建线程的方式,如果是0,表示线程一被创建就被立即执行,如果是CREATE_SUSPENDED,
表示线程一被创建先暂停,并不执行,在XP以上的系统中此参数还可以结合一个STACK_SIZE_PARAM_IS_A_RESERVATION
用于指出设置dwStackSize起始只是为线程栈保留的虚拟地址空间的大小,并不需要实际提交那么多的物理页面
如果没有指定这个标志位,那么dwStackSize也是实际提交内存的大小值
lpThreadId则用于得到线程唯一的标识符
1、参数的结果是随机的,表明CPU调用线程完全是随机的
2、这充分说明Windows线程调度机制的最终行为是随机的,是一个抢占式多任务的系统
3、因此分析多线程程序的时候,一般不能假设某个线程会被先调度,某个线程会被后调度,也即
不能假设线程执行的顺序这样的行为
4、虽然windows调度程序时间是按分时多任务方式来轮流调度线程的,而且这个时间片是20ms,
但是从宏观的角度来看,比如1秒的时间粒度,这些线程可以被认为是“同时”运行的
5、这些信息说明,无论线程调度如何执行,在分析时始终认为这些线程实际上时并行执行的,
这样就可以把繁琐的分析简单化
6、下面的例子只是用了一个线程函数,而这个函数起始访问了一个公共资源STDOUTPUT
7、在windows系统中,大多数内核对象的操作室严格穿行化的,因此无论线程如何并发的执行,
最终输出的结果都是完整有序的,因为调用的WriteConsole方法本身是严格串行化的(否则输出是混乱的)
8、有时虽然线程本身是被认为是并发的,但在实际中又确实需要对他们执行的顺序进行一些不要的控制和管理,
这是就需要进行多线程并发控制
#include
#include
#include
#include
#defineGRS_ALLOC(sz)HeapAlloc(GetProcessHeap(),0,sz)
#defineGRS_CALLOC(sz)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#defineGRS_SAFEFREE(p)if(NULL!=p){HeapFree(GetProcessHeap(),0,p);p=NULL;}
#defineGRS_USEPRINTF()TCHARpBuf[1024]={}
#defineGRS_PRINTF(…)\
StringCchPrintf(pBuf,1024,__VA_ARGS__);\
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuf,lstrlen(pBuf),NULL,NULL);
#defineMAX_THREADS10//最大线程数
DWORDWINAPIMyThreadFunction(LPVOIDlpParam);
voidErrorHandler(LPTSTRlpszFunction);
//自定义线程数据
typedefstructMyData
{
intval1;
intval2;
}MYDATA,*PMYDATA;
int_tmain()
{
PMYDATApDataArray[MAX_THREADS];
DWORDdwThreadIdArray[MAX_THREADS];
HANDLEhThreadArray[MAX_THREADS];
//创建线程循环
for(inti=0;i
{
pDataArray[i]=(PMYDATA)GRS_CALLOC(sizeof(MYDATA));
pDataArray[i]->val1=i;
pDataArray[i]->val2=i+100;
hThreadArray[i]=CreateThread(NULL,0,MyThreadFunction,pDataArray[i],0,&dwThreadIdArray[i]);
if(hThreadArray[i]==NULL)
{
ErrorHandler(_T(“CreateThread”));
ExitProcess(3);
}
}
WaitForMultipleObjects(MAX_THREADS,hThreadArray,TRUE,INFINITE);
for(inti=0;i
{
CloseHandle(hThreadArray[i]);
GRS_SAFEFREE(pDataArray[i]);
}
_tsystem(_T(“PAUSE”));
return0;
}
DWORDWINAPIMyThreadFunction(LPVOIDlpParam)
{
//线程函数
GRS_USEPRINTF();
PMYDATApDataArray=(PMYDATA)lpParam;
GRS_PRINTF(_T(“Parameters=%d,%d\n”),pDataArray->val1,pDataArray->val2);
return0;
}
voidErrorHandler(LPTSTRlpszFunction)
{
GRS_USEPRINTF();
LPVOIDlpMsgBuf;
DWORDdw=GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM|
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0,NULL
);
GRS_PRINTF(_T(“%sfailedwitherror%d:%s”),lpszFunction,dw,lpMsgBuf);
LocalFree(lpMsgBuf);
C++ 多线程 CreateThread函数使用例1
#include
#include
#include
#include
#include
#include
#include
//头文件引用较多,有一些与本程序无关
/*
HANDLEWINAPICreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,//线程安全相关的属性,常置为NULL
SIZE_TdwStackSize,//新线程的初始化栈在大小,可设置为0
LPTHREAD_START_ROUTINElpStartAddress,//被线程执行的回调函数,也称为线程函数
LPVOIDlpParameter,//传入线程函数的参数,不需传递参数时为NULL
DWORDdwCreationFlags,//控制线程创建的标志
LPDWORDlpThreadId//传出参数,用于获得线程ID,如果为NULL则不返回线程ID
);
*/
usingnamespacestd;
volatileintb=0;
DWORDWINAPIThreadProc(LPVOIDlpParameter)
{
inti=10000;
int*p=(int*)lpParameter;
while(i–)
{
(*p)++;
b++;
}
return0;
}
intmain(intargc,char*argv[])
{
inta=0;
HANDLEhThread1=CreateThread(NULL,0,ThreadProc,&a,0,NULL);
HANDLEhThread2=CreateThread(NULL,0,ThreadProc,&a,0,NULL);
HANDLEhThread3=CreateThread(NULL,0,ThreadProc,&a,0,NULL);
HANDLEhThread4=CreateThread(NULL,0,ThreadProc,&a,0,NULL);
HANDLEhThread5=CreateThread(NULL,0,ThreadProc,&a,0,NULL);
Sleep(1000);
CloseHandle(hThread1);
CloseHandle(hThread2);
CloseHandle(hThread3);
CloseHandle(hThread4);
CloseHandle(hThread5);
cout<
cout<
system(“pause”);
return0;
}
使用实例2:
1.定义的全局变量DWORDWINAPIClientThread(LPVOIDlpParam);
structClientInfo
{
SOCKETsock;
SOCKADDR_INclientAddr;定义地址族
};
2.使用方法HANDLEhThread;DWORDdwThread;
structClientInfo*pClientInfo=NULL;
pClientInfo=(structClientInfo*)malloc(sizeof(structClientInfo));
hThread=CreateThread(NULL,0,ClientThread,(LPVOID)pClientInfo,0,&dwThread);//free(pClientInfo);if(hThread==NULL){AfxMessageBox(“ThreadCreatFailed!\n”);return;}
CloseHandle(hThread);3.线程函数的实现DWORDWINAPIClientThread(LPVOIDlpParam){structClientInfo*pClinetInfo=(structClientInfo*)lpParam;SOCKETsock=pClinetInfo->sock;SOCKADDR_INaddrClient=pClinetInfo->clientAddr;free(lpParam);CTCPServerDlg*dlg=(CTCPServerDlg*)AfxGetApp()->GetMainWnd();
while(1)
{
…..
Sleep(200);
}
return0;
}
实例3://ThreadBase.h
#pragmaonce#includeclassCThreadBase
{public:
CThreadBase(void);~CThreadBase(void);staticDWORDWINAPIThreadProc(PVOIDpParam);virtualvoidRun()=0;voidStart();
private:
HANDLEm_hThread;
DWORDm_dwThreadID;
};
//ThreadBase.cpp#include“StdAfx.h”#include“ThreadBase.h”
CThreadBase::CThreadBase(void)
{
m_hThread=CreateThread(NULL,0,ThreadProc,this,CREATE_SUSPENDED,&m_dwThreadID);
}
CThreadBase::~CThreadBase(void)
{
CloseHandle(m_hThread);
}
DWORDWINAPICThreadBase::ThreadProc(PVOIDpParam)
{
if(NULL!=pParam)
{
((CThreadBase*)pParam)->Run();
}return0;
}voidCThreadBase::Start()
{
ResumeThread(m_hThread);
}