CreateThread和_beginthreadex的区别
来源:互联网 发布:俄罗斯av 女星 知乎 编辑:程序博客网 时间:2024/06/07 05:10
网址:
在使用VS创建一个工程时,我们可以选择使用的run-time library,在run-time libary的下拉菜单中,有 Single-Threaded, Multithreaded, MultiThreaded DLL等好几种选项,不同的选项会为我们链接不同的C++ rum-time库。 之所以run-time库会有单线程和多线程的区别,是因为标准C运行库在最初设计时,并没有考虑到其将被运用于多线程的应用程序,这将会引起一些问题。 例如对于C运行期的全局变量errno,我们在多线程环境下,不能保证在设置errno和获取errno之间,没有其他线程对这个全局变量进行了设置,这就会产生一定的问题。而要解决这个问题,我们可以使用线程专属全局变量 ,这个概念我将在以后讲到,但在这个地方,C++ run-time使用的方式是在创建新线程时,为每一个线程分配一个数据块,来保存这些全局的信息。 在Windows下创建线程调用的是Windows的API函数CreateThread,但CreateThread只是一个与操作系统相关的函数,负责在操作系统内部创建线程内核对象,为线程分配栈空间。为线程的运行准备适宜的条件,并不是操作系统应该考虑的事情。比如说,C++ run-time需要在创建线程时,创建一个线程专属的errno变量,但可能其他的运行环境又没有这一项要求,我们不能强制要求Windows操作系统去迎合C++ run-time的需求。 CreateThread并不能正确地初始化C++ run-time对于多线程环境的要求,因此C++ run-time提供了自己的线程创建函数 _beginthreadex,其函数原型如下: 这个函数的参数和CreateThread的参数基本一致,不同的是参数类型不同。这是因为C++ run-time并不从属于操作系统,不应当对操作系统的数据类型有任何依赖。因此我们可以看到 _beginthreadex 函数的参数完全是基本的C++数据类型。 _beginthreadex 函数将会创建线程专属的数据块,并对其进行初始化,而后调用操作系统的线程创建函数以创建一个线程,其伪码如下: 我们可以看到,_beginthreadex首先创建了一个线程专属数据块,这个数据块中自然就保存了errno之类的线程专属数据,至于如何获取和设置这些数据,稍后我会提到。 创建线程仍然是调用的Windows API函数CreateThread,因为线程的创建与操作系统息息相关,我们唯有通过其API函数CreateThread才可以创建之。 _beginthreadex 将线程的入口函数变更为了 _threadstartex,我们可以看其伪码: 我们可以看到 _threadstartex 仍然是调用了 _beginthreadex 函数中最初传入的线程函数,不同的是,在调用线程函数之前,我们使用了异常捕获,防止线程函数崩溃导致程序崩溃。在线程函数执行完毕后,_threadstartex会紧接着调用 _endthreadex函数,这个函数的作用有两点: 1. 释放线程专属数据块,避免内存泄漏 至此我们可以知道,CreateThread和_beginthreadex两个函数的区别在于: CreateThread是操作系统提供的创建线程的API,_beginthreadex是C++ run-time提供的用于对线程进行初始化,创建线程转悠数据块的函数。其内部创建线程的操作,仍然通过CreateThread来实现。 我们在编写C++程序创建线程时,应当使用_beginthreadex,而绝不要使用CreateThread,否则会引起错误。 在我们使用_beginthreadex函数时,必须选择run-time链接选项为多线程库,否则会出现找不到_beginthreadex的错误。 我们之前提到过errno这个全局变量,在run-time为多线程库的时候,它实际上是一个宏: 我们在选择多线程库后,使用errno时,实际上是调用了多线程库中的 _errno()函数,这个函数会将线程专属数据块中的errno值获取出来。 可以注意到,_errno() 实际上是取得了线程专属数据块中errno的地址,因此我们也可以对errno进行设置,其行为就如同直接使用一个int类型变量一样。unsigned
long
_beginthreadex(
void
* security,
unsigned stack_size,
unsigned (*start_address)(
void
*),
void
* arglist,
unsigned initflag,
unsigned* thrdaddr);
unsigned
long
_beginthreadex(
void
* security,
unsigned stack_size,
unsigned (*start_address)(
void
*),
void
* arglist,
unsigned initflag,
unsigned* thrdaddr)
{
_ptiddata ptd;
// 指向线程专属数据块的指针,这个结构不作详细介绍,只需知道其中包含线程专属全局变量
unsigned
long
thdl;
// 线程句柄
// 申请线程专属数据块
ptd = _calloc_crt(1,
sizeof
(
struct
tiddata));
initptd(ptd);
// 初始化
// 保存一些需要的信息
ptd->_initaddr = (
void
*)pfnStartAddr;
// 保存线程函数地址
ptd->_initarg = pvParam;
// 保存线程函数的参数
// 创建线程
thdl = (unsigned
long
) CreateThread(pas, cbStack, _threadstartex, (
PVOID
)ptd, fdwCreate, pdwThreadID);
if
(thdl == NULL)
{
_free_crt(ptd);
return
0;
}
return
thdl;
}
static
unsigned
long
WINAPI _threadstartex(
void
* ptd)
{
// 保存ptd,我们在其他地方会再获取ptd
TlsSetValue(__tlsidnex, ptd);
((_ptiddata) ptd)->_tid = GetCurrentThreadId();
__try
{
unsigned ret = ptd->_initaddr(ptd->_initarg);
_endthreadex(ret);
}
__except()
{
_exit(GetExceptionCode());
}
return
0;
}
2. 调用ExitThread退出线程,将退出码写入到线程内核对象中#if defined(_MT) || defined(_DLL)
extern
int
* __cdecl _errno(
void
);
#define errno (*_errno())
#else
extern
int
errno
;
#endif
- CreateThread和_beginthreadex的区别
- CreateThread和_beginthreadex的区别
- CreateThread和_beginthreadex区别
- CreateThread 和_beginthreadex区别
- _beginthreadex和CreateThread的区别和联系
- CreateThread、_beginthreadex和AfxBeginThread的区别
- 关于_beginthreadex和CreateThread的区别
- 关于_beginthreadex和CreateThread的区别
- 关于_beginthreadex和CreateThread的区别zhuantie
- FAQ6:_Beginthreadex 和 CreateThread 的区别
- 关于_beginthreadex和CreateThread的区别
- 关于_beginthreadex和CreateThread的区别
- CreateThread、_beginthreadex和AfxBeginThread的区别
- _beginthreadex与createthread和AfxBeginThread的区别
- _beginthreadex与createthread和AfxBeginThread的区别
- CreateThread、_beginthreadex和AfxBeginThread 的区别
- 关于_beginthreadex和CreateThread的区别
- _beginthreadex与createthread和AfxBeginThread的区别
- imx515 开发板Android源代码编译过程
- Gallery 与ImageSwitcher的结合使用
- KMP字符串匹配算法 通俗理解
- 网页版excel数据批量导入数据库
- expdp/impdp及exp/imp
- CreateThread和_beginthreadex的区别
- 如何在模拟器上安装apk软件
- 问题解决
- 软件测试俱乐部章程
- linux下各种压缩文件以及相应的解压方法
- 在Ubuntu中用Android NDK编译FFmpeg
- Boost 库中的实用工具类使用入门
- VS开发工具价格
- 修改网卡物理地址