当前位置:  开发笔记 > 编程语言 > 正文

Windows线程:_beginthread vs _beginthreadex vs CreateThread C++

如何解决《Windows线程:_beginthreadvs_beginthreadexvsCreateThreadC++》经验,为你挑选了8个好方法。

什么是更好的方式来启动一个线程_beginthread,_beginthreadxCreateThread

我试图确定什么是优势/劣势_beginthread,_beginthreadexCreateThread.所有这些函数都返回一个新创建的线程的线程句柄,我已经知道CreateThread在发生错误时提供了一些额外的信息(可以通过调用来检查GetLastError)......但是当我发现时,我应该考虑哪些事情?我用这些功能?

我正在使用Windows应用程序,因此跨平台兼容性已经不可能了.

我已经浏览了msdn文档,但我无法理解,例如,为什么有人会决定使用_beginthread而不是CreateThread,反之亦然.

干杯!

更新:好的,感谢所有的信息,我也读过几个我不能打电话的地方,WaitForSingleObject()如果我用的话_beginthread(),但是如果我_endthread()在线程中打电话应该不行吗?这有什么交易?



1> Drew Hall..:

CreateThread() 是一个原始的Win32 API调用,用于在内核级别创建另一个控制线程.

_beginthread()&_beginthreadex()CreateThread()在后台调用的C运行时库调用.一旦CreateThread()返回,_beginthread/ex()就会负责额外的簿记,以使C运行时库在新线程中可用且一致.

在C++中,您几乎肯定会使用,_beginthreadex()除非您根本不会链接到C运行时库(也就是MSVCRT*.dll/.lib).


这已不再像过去那样真实.CRT将在CreateThread()创建的线程中正常运行,但signal()函数除外.对于使用CRT创建的CreateThread()创建的每个线程,都会有一个小的内存泄漏(~80个字节),但它将正常运行.有关详细信息,请参阅:http://support.microsoft.com/default.aspx/kb/104641
`_begin`函数以下划线*开头,因为*Microsoft开始更严格地遵循标准.在C运行时中,带有下划线的名称是为实现保留的(并且实现可以记录它们以供最终用户使用,就像这些一样).`beginthreadex()`是允许用户使用的名称.如果C运行时使用它,那么它可能与用户有合法权利期望使用的最终用户符号冲突.请注意,Win32 API不是C运行时的一部分,它们使用用户的命名空间.
@Roger - 除非你使用`_beginthread()`
@bobobobo:好问题.我只能推测MS原本打算将`_begin`例程作为内部调用,而`CreateThread`应该是每个人都会调用的API函数.另一个可能的解释是,MS有着悠久而光荣的历史,无视标准并做出关于命名的非常糟糕的决定.
@Lothar:在Win32 API调用`CreateThread`和CRT调用`_beginthread/ex`之间存在**差异,并且在线程上调用CRT时,应始终使用`_beginthread/ex`创建.如果不这样做,可能不再有内存泄漏.但是,例如,当你调用`CreateThread`时,你肯定不会正确初始化你的浮点环境.[更多](https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453.aspx):*"如果使用**CreateThread**创建的线程调用CRT,CRT可能会终止在低内存条件下的过程."*

2> Michael Burr..:

_beginthread()和之间有几点不同_beginthreadex(). _beginthreadex()被制作成更像CreateThread()(在两个参数和它的行为方式).

正如Drew Hall所提到的,如果您正在使用C/C++运行时,则必须使用_beginthread()/ _beginthreadex()而不是CreateThread()使运行时有机会执行它自己的线程初始化(设置线程本地存储等).

在实践中,这意味着CreateThread()您的代码几乎不会直接使用它.

对于MSDN文档_beginthread()/ _beginthreadex()有相当多的细节上的差异-更重要的一个是,因为通过创建一个线程的线程处理_beginthread()得到由CRT自动关闭,当线程退出,"如果由_beginthread出口产生的线程很快,返回给_beginthread调用者的句柄可能无效,或者更糟糕的是,指向另一个线程".

这是_beginthreadex()CRT来源的评论必须说:

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

2013年1月更新:

VS 2012的CRT还执行了一些额外的初始化_beginthreadex():如果进程是"打包应用程序"(如果返回了一些有用的东西GetCurrentPackageId()),运行时将在新创建的线程上初始化MTA.


当CreateThread()得到保证时,*是*适当的时间,但老实说,你真的必须尽力去做.我们正在谈论完全缺乏任何可移植的东西并编写一个专门的WIN32 API DLL或App.不包括C运行时调用.甚至STL的使用也是有限的,因为你必须提供自定义分配器才能使用WIN32内存管理功能.使用Developer Studio执行此操作的设置本身就是一项工作,但对于只有尽可能小占用空间的WIN32库,可以完成.但是,除了极少数人之外,几乎所有人都不会感到血腥.

3> MSN..:

一般来说,正确的做法是调用_beginthread()/_endthread()(或ex()变体).但是,如果您使用CRT作为一个.dll,在CRT状态将被正确的初始化和销毁CRT的DllMain将被用DLL_THREAD_ATTACHDLL_THREAD_DETACH打电话时CreateThread(),并ExitThread()分别或返回.

DllMain可以在VC\crt\src\crtlib.c下的VS的安装目录中找到CRT 的代码.



4> Constantin..:

这是代码的核心_beginthreadex(参见crt\src\threadex.c):

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

其余的_beginthreadex初始化CRT的每线程数据结构.

使用的优点_beginthread*是您的线程CRT调用将正常工作.



5> 小智..:

您应该使用_beginthread_beginthreadex允许C运行时库自己进行线程初始化.只有C/C++程序员需要知道这一点,因为他们现在应该使用他们自己的开发环境的规则.

如果你使用,_beginthread你不需要打电话,CloseHandle因为RTL会为你做.这就是为什么你不能在手柄上等待的原因_beginthread.也_beginthread导致混乱,如果线程函数立即退出(快速)作为启动线程我可以左手拿着无效的线程句柄,它刚刚推出的线程.

_beginthreadex句柄可以用于等待,但也需要显式调用CloseHandle.这是使他们安全使用等待的一部分.使其完全万无一失的另一个问题是始终启动线程暂停.检查成功,记录句柄等.恢复线程.这是防止线程在启动线程可以记录其句柄之前终止所必需的.

最佳做法是使用_beginthreadex,记录句柄后启动暂停然后恢复,等待处理即可,CloseHandle必须调用.



6> Jaywalker..:

CreateThread()用于在代码中使用任何CRT函数时发生内存泄漏._beginthreadex()具有相同的参数,CreateThread()并且它比它更通用_beginthread().所以我建议你使用_beginthreadex().


是的,它仅适用于MSVC++ 6.0 Service Pack 5及更早版本.(请参阅"适用于"可扩展下拉列表).如果您使用的是VC7或更高版本,今天这不是问题.
你歪曲了这些信息:`CreateThread`确实**不会**泄漏内存.当从一个尚未正确初始化的线程调用时,它确实是CRT.

7> Michael Burr..:

关于你更新的问题:" WaitForSingleObject()如果我使用的话,我也会在几个地方看到我不能打电话_beginthread(),但如果我_endthread()在线程中打电话不应该那么有用吗?"

通常,您可以将线程句柄传递给WaitForSingleObject()(或等待对象句柄的其他API),直到线程完成为止.但是,调用_beginthread()时创建的线程句柄在_endthread()调用时会关闭(可以显式完成,也可以在线程过程返回时由运行时隐式完成).

问题在文档中提到WaitForSingleObject():

如果在等待仍处于暂挂状态时关闭此句柄,则函数的行为未定义.



8> bobobobo..:

看功能签名,CreateThread几乎完全相同_beginthreadex.

_beginthread,_beginthreadx vsCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

这里的评论说_beginthread可以使用__cdecl或者__clrcall调用约定作为起始点,并且_beginthreadex可以使用__stdcall或者__clrcall用于起始点.

我认为人们对内存泄漏的评论CreateThread已有十多年的历史,应该被忽略.

有趣的是,这两个_beginthread*函数实际调用CreateThread的引擎盖下,在C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src我的机器上.

// From ~line 180 of beginthreadex.c
/*
 * Create the new thread using the parameters supplied by the caller.
 */
if ( (thdl = (uintptr_t)
      CreateThread( (LPSECURITY_ATTRIBUTES)security,
                    stacksize,
                    _threadstartex,
                    (LPVOID)ptd,
                    createflag,
                    (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
{
        err = GetLastError();
        goto error_return;
}


[评论,为什么你不应该调用CreateThread并混合在该线程上的CRT调用(绝对不是十年之久,**绝对**不应该被忽略)](https://msdn.microsoft.com/en- us/library/windows/desktop/ms682453.aspx):*"如果使用CreateThread创建的线程调用CRT,则CRT可能会在内存不足的情况下终止进程."*
推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有