一、解释

(1)如果你正在编写C/C++代码,决不应该调用CreateThread。相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex。如果不使用Microsoft的VisualC++编译器,你的编译器供应商有它自己的CreateThread替代函数。不管这个替代函数是什么,你都必须使用。

(2)因为_beginthreadex和_endthreadex是CRT线程函数,所以必须注意编译选项runtimelibaray的选择,使用MT或MTD。[MultiThreaded , Debug MultiThreaded]。

(3)_beginthreadex函数的参数列表与CreateThread函数的参数列表是相同的,但是参数名和类型并不完全相同。这是因为Microsoft的C/C++运行期库的开发小组认为,C/C++运行期函数不应该对Windows数据类型有任何依赖。_beginthreadex函数也像CreateThread那样,返回新创建的线程的句柄。

下面是关于_beginthreadex的一些要点:

1)每个线程均获得由C/C++运行期库的堆栈分配的自己的tiddata内存结构。(tiddata结构位于Mtdll.h文件中的VisualC++源代码中)。

2)传递给_beginthreadex的线程函数的地址保存在tiddata内存块中。传递给该函数的参数也保存在该数据块中。

3)_beginthreadex确实从内部调用CreateThread,因为这是操作系统了解如何创建新线程的唯一方法。

4)当调用CreatetThread时,它被告知通过调用_threadstartex而不是pfnStartAddr来启动执行新线程。还有,传递给线程函数的参数是tiddata结构而不是pvParam的地址。

5)如果一切顺利,就会像CreateThread那样返回线程句柄。如果任何操作失败了,便返回NULL。

(4)_endthreadex的一些要点:

C运行期库的_getptd函数内部调用操作系统的TlsGetValue函数,该函数负责检索调用线程的tiddata内存块的地址。

然后该数据块被释放,而操作系统的ExitThread函数被调用,以便真正撤消该线程。当然,退出代码要正确地设置和传递。

(5)虽然也提供了简化版的的_beginthread和_endthread,但是可控制性太差,所以一般不使用。

(6)线程handle因为是内核对象,所以需要在最后closehandle。

(7)更多的API:

HANDLE GetCurrentProcess();HANDLE GetCurrentThread();DWORD GetCurrentProcessId();DWORD GetCurrentThreadId()。DWORD SetThreadIdealProcessor(HANDLE hThread,DWORDdwIdealProcessor);BOOL SetThreadPriority(HANDLE hThread,int nPriority);BOOL SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);BOOL GetThreadContext(HANDLE hThread,PCONTEXTpContext);BOOL SwitchToThread();

二、为什么用_beginthreadex而不是CreateThread?

为什么要用C运行时库的_beginthreadex代替操作系统的CreateThread来创建线程?

你也许会说我一直用CreateThread来创建线程,一直都工作得好好的,为什么要用_beginthreadex来代替CreateThread,下面让我来告诉你为什么。

首先要从标准C运行库与多线程的矛盾说起,标准C运行库在1970年被实现了,由于当时没任何一个操作系统提供对多线程的支持。因此编写标准C运行库的程序员根本没考虑多线程程序使用标准C运行库的情况。比如标准C运行库的全局变量errno。很多运行库中的函数在出错时会将错误代号赋值给这个全局变量,这样可以方便调试。但如果有这样的一个代码片段:

if (system("notepad.exe readme.txt") == -1)
{switch(errno){...//错误处理代码}
}

假设某个线程A在执行上面的代码,该线程在调用system()之后且尚未调用switch()语句时另外一个线程B启动了,这个线程B也调用了标准C运行库的函数,不幸的是这个函数执行出错了并将错误代号写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。这种情况必须要加以避免!因为不单单是这一个变量会出问题,其它像strerror()、strtok()、tmpnam()、gmtime()、asctime()等函数也会遇到这种由多个线程访问修改导致的数据覆盖问题。

为了解决这个问题,Windows操作系统提供了这样的一种解决方案——每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而且这块内存区域的创建就是由C/C++运行库函数_beginthreadex()来负责的。

上述代码中的errno全局变量,在最新的代码中已经变成了一个宏#define errno (*_errno()),最终调用的代码函数如下:

int * __cdecl _errno(void)
{//线程相关_ptiddata ptd = _getptd_noexit();if (!ptd) {return &ErrnoNoMem;} else {return ( &ptd->_terrno );}
}

这里的errno不在是全局变量,而是函数;该函数返回每个线程各自errno。因此,解决了数据覆盖问题。

为了印象深刻,我们可以查看该函数的具体实现,_beginthreadex的实现可以在vs2008安装目录下找到,其文件和路径如下:

...\VC\crt\src\threadex.c

简言而之,_beginthreadex在内部调用了CreateThread,在调用之前_beginthreadex做了很多的工作,从而使得它比CreateThread更安全。因此,在实际编码中,我们创建线程需要使用_beginthreadex函数。


参考文章:
原文:https://blog.csdn.net/laoyang360/article/details/7720656
原文:https://blog.csdn.net/morewindows/article/details/7421759

_beginthreadex 创建多线程解读相关推荐

  1. _beginThreadex创建多线程解读

    _beginThreadex创建多线程解读 一.须要的头文件支持 #include <process.h>         // for _beginthread() 须要的设置:Proj ...

  2. C++多线程实例(_beginThreadex创建多线程)

    C++多线程(二)(_beginThreadex创建多线程) C/C++ Runtime 多线程函数 一 简单实例(来自codeprojct:http://www.codeproject.com/us ...

  3. _beginthreadex创建多线程的用法

    一.实例 #include <stdio.h> #include <string> // for STL string class #include <windows.h ...

  4. 采用_beginthread/_beginthreadex函数创建多线程

    1.CRT简介: CRT: (C Runtime Library)即C运行时库,是系统运行的基础,包含了c常用的函数集(如:printf,malloc,strcpy等),为运行main做了初始化环境变 ...

  5. 转:MFC中创建多线程

    MFC中创建多线程 MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员,可 ...

  6. java多线程w3c_Java创建多线程的三种方式

    前言 这篇文章主要讲述线程的概念.组成.Java创建多线程的三种方式以及线程的类型. 线程概念 线程和进程的区别 **进程:**正在运行的程序,例如:你打开 的qq音乐.exe程序,其由PCB(进程控 ...

  7. python3创建多线程的几种方法

    python3创建多线程主要有下面两种方法:函数.类 1.函数创建多线程 python3中,提供了一个内置模块threading.Thread,可以很方便的创建多线程,threading.Thread ...

  8. java 创建多线程_Java创建多线程

    Java创建多线程 下一节> 到目前为止,我们仅用到两个线程:主线程和一个子线程.然而,你的程序可以创建所需的更多线程.例如,下面的程序创建了三个子线程: // Create multiple ...

  9. 多线程初探:三种方式创建多线程详细示例

    多线程即在同一时间,可以做多件事情. 创建多线程有3种方式,分别是继承线程类,实现Runnable接口,匿名类 一:线程概念 首先要理解进程(Processor)和线程(Thread)的区别 进程:启 ...

最新文章

  1. 【青少年编程】【三级】青蛙捕虫
  2. 微软开发中心的rss历史记录(24)
  3. python ctypes教程_Python ctypes: Python file object - C FILE * | 易学教程
  4. 8.1 A Bayesian Methodology for Systemic Risk Assessment in Financial Networks(3)
  5. 平板xmind怎么添加父主题_xmind 怎么插入子主题
  6. Linux shell 常用命令
  7. DevExpress之TreeList用法
  8. k8s高可用二进制部署
  9. php如何把汉字转换为拼音,php 把汉字转换为拼音 php 如何把拼音转换汉字
  10. 樱花漫地集于我心,蝶舞纷飞祈愿相随 発生:genesis 发生:genesis
  11. 关于arduino的各种网站
  12. 10代cpu能装服务器系统不,第10代CPU可以装Windows7吗
  13. Day10_GY39
  14. spring aop 执行顺序(@Before @Around @After @AfterReturning @AfterThrowing)
  15. 家园防线 | 斐乐的手敲大型庭院物联网灌溉系统(持续更新)
  16. python什么意思g_在外行人看来,Python字符串格式“g”实际意味着什么?
  17. 绩效考核-项目经理绩效考核指标
  18. 制作CRM管理系统04(客户增加)
  19. android 切换摄像头加动画,android前后摄像头切换
  20. 机器学习(十二):人工神经网络(ANN)

热门文章

  1. 尚硅谷课程vue学习(一)
  2. uni-app实现蓝牙打印小票
  3. kali安装图文教程
  4. 云音乐用户增长预测之Prophet模型
  5. python如何找对象_【从Python开始学编程】帮Python找对象
  6. android开发三大框架!毕业一年萌新的Android大厂面经,2年以上经验必看
  7. Spring优雅停机
  8. 【CVPR2022论文精读DiffFace】DiffFace: Diffusion-based Face Swapping with Facial Guidance
  9. python获取梦幻西游鼠标偏移坐标
  10. 【自动驾驶】路径规划—— Dubins 曲线推导(基于向量的方法)