多线程学习笔记之初始_beginthreadex()

本文介绍了Windows环境下使用_beginthreadex()函数创建多线程的方法,包括如何传递参数、获取线程ID及退出码等,并分享了多线程编程的一些实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    最近有点闲,于是想探究下多线程的使用,先是研究的windows下的多线程,在此记录笔记。通过上网搜索多线程的知识,发现windows下创建多线程的函数有CreateThread()和_beginthreadex()。了解了这两个函数的区别,都推荐使用_beginthreadex()函数而不是CreateThread(),主要是为了在多线程中使用c运行时库。标准c库实现于1970年代,那时还没有多线程技术,c运行时库也就不支持多线程技术,比如原来的将errno置出错信息的编程方法运用在多线程中就不适合了。windows给出的解决方法就是为每一个线程在内存分配内存块,线程的相关数据代码存放在各自的内存块中,各个线程使用和修改各自的内存块,就不会互相影响了。

_beginthreadex()函数在msdn中的定义如下:

uintptr_t _beginthreadex( // NATIVE CODE
   void *security,
   unsigned stack_size,
   unsigned ( __stdcall *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

函数说明:

第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置(设置为NULL,线程句柄无法被子线程继承)。

第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。

第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。

第四个参数是传给线程函数的参数。

第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()

第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。

_beginthreadex()函数使用如下:

// MultiThread.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <process.h>                          //包含_beginthreadex()的头文件
#include <windows.h>                          //句柄头文件

using namespace std;

unsigned __stdcall threadFun(void *)          //线程调用函数
{
	for (int i=0;i<10;++i)
	{
		cout<<i<<" ";
	}	
	cout<<endl;
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	   unsigned int thID1;                                    //线程ID号
	   HANDLE hth1;                                  //线程句柄
				hth1 = (HANDLE)_beginthreadex(NULL,0,threadFun,NULL,0,&thID1);
				WaitForSingleObject(hth1,INFINITE);          //等待线程运行结束
				DWORD exitCode1;
				GetExitCodeThread(hth1,&exitCode1);          //获得线程的推出码

				cout<<"exitcode: "<<exitCode1<<" "<<endl;
				cout<<"ID: "<<thID1<<" "<<endl;
}
结果如下:


上边的函数是不带参数的,如果带参数怎么办呢,可以给线程函数传递参数,如下:

<span style="font-size:18px;">// MultiThread.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <process.h>                               //包含_beginthreadex()的头文件
#include <windows.h>                               //句柄头文件

using namespace std;

struct Arg                                         //参数结构体
{
	double d_;
	string str_;
	Arg(double dd,string ss):d_(dd),str_(ss){}
};

unsigned __stdcall threadFun(void *)               //线程调用函数
{
	for (int i=0;i<10;++i)
	{
		cout<<i<<" ";
	}	
	cout<<endl;
	return 1;
}

unsigned __stdcall threadFunArg(void *arglist)     //线程调用函数 通过结构体来传入多个参数
{
	cout<<endl;
	Arg *p	= (Arg*)arglist;                           //反解输入参数
	cout<<p->d_<<" "<<p->str_<<endl;
	return 2;
}

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned int thID1,thID2;
	HANDLE hth1,hth2;
	Arg arg(3.14,"hello world!");

	hth1 = (HANDLE)_beginthreadex(NULL,0,threadFun,NULL,0,&thID1);   //创建两个线程
	hth2 = (HANDLE)_beginthreadex(NULL,0,threadFunArg,&arg,0,&thID2);

	WaitForSingleObject(hth1,INFINITE);                             //等待线程运行结束
	WaitForSingleObject(hth2,INFINITE);

	DWORD exitCode1,exitCode2;
	GetExitCodeThread(hth1,&exitCode1);                             //获得线程的退出码
	GetExitCodeThread(hth2,&exitCode2);

	cout<<"exitcode: "<<exitCode1<<" "<<exitCode2<<endl;
	cout<<"ID: "<<thID1<<" "<<thID2<<endl;
}</span>

    这就是我最近关于多线程的一些实践,此外,还有些个人观点:

(1)首先判断出程序中耗时的部分,对耗时的地方用多线程进行处理。

(2)创建几个线程,不宜过多,也不宜过少,最好跟计算机的核数相同。

(3)多个线程中,有快有慢,如果快的用很久时间等待慢的线程运行完,那多线程就没太大意义,劲量使多个线程的运行时间差不多。

(4)要注意线程的同步问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值