Windows 线程:_beginthread 与 _beginthreadex 与 CreateThread C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/331536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Windows threading: _beginthread vs _beginthreadex vs CreateThread C++
提问by Kiril
What's a better way to start a thread, _beginthread
, _beginthreadx
or CreateThread
?
启动线程的更好方法是什么,_beginthread
,_beginthreadx
或CreateThread
?
I'm trying to determine what are the advantages/disadvantages of _beginthread
, _beginthreadex
and CreateThread
. All of these functions return a thread handle to a newly created thread, I already know that CreateThread provides a little extra information when an error occurs (it can be checked by calling GetLastError
)... but what are some things I should consider when I'm using these functions?
我试图确定_beginthread
,_beginthreadex
和的优点/缺点是什么CreateThread
。所有这些函数都会向新创建的线程返回一个线程句柄,我已经知道 CreateThread 在发生错误时提供了一些额外的信息(可以通过调用来检查GetLastError
)……但是我应该考虑哪些事情? m 使用这些功能?
I'm working with a windows application, so cross-platform compatibility is already out of the question.
我正在使用 Windows 应用程序,因此跨平台兼容性已经不可能了。
I have gone through the msdn documentation and I just can't understand, for example, why anybody would decide to use _beginthread instead of CreateThread or vice versa.
我已经阅读了 msdn 文档,但我无法理解,例如,为什么有人会决定使用 _beginthread 而不是 CreateThread,反之亦然。
Cheers!
干杯!
Update:
OK, thanks for all the info, I've also read in a couple of places that I can't call WaitForSingleObject()
if I used _beginthread()
, but if I call _endthread()
in the thread shouldn't that work? What's the deal there?
更新:好的,感谢您提供的所有信息,我还在几个地方读到了WaitForSingleObject()
如果我使用了就无法调用的地方_beginthread()
,但是如果我调用_endthread()
线程不应该这样吗?那里有什么交易?
采纳答案by Drew Hall
CreateThread()
is a raw Win32 API call for creating another thread of control at the kernel level.
CreateThread()
是一个原始的 Win32 API 调用,用于在内核级别创建另一个控制线程。
_beginthread()
& _beginthreadex()
are C runtime library calls that call CreateThread()
behind the scenes. Once CreateThread()
has returned, _beginthread/ex()
takes care of additional bookkeeping to make the C runtime library usable & consistent in the new thread.
_beginthread()
&_beginthreadex()
是CreateThread()
在幕后调用的 C 运行时库调用。一旦CreateThread()
返回,_beginthread/ex()
就负责额外的簿记,以使 C 运行时库在新线程中可用并保持一致。
In C++ you should almost certainly use _beginthreadex()
unless you won't be linking to the C runtime library at all (aka MSVCRT*.dll/.lib).
在 C++ 中,您几乎肯定应该使用,_beginthreadex()
除非您根本不会链接到 C 运行时库(又名 MSVCRT*.dll/.lib)。
回答by Michael Burr
There are several differences between _beginthread()
and _beginthreadex()
. _beginthreadex()
was made to act more like CreateThread()
(in both parameters and how it behaves).
_beginthread()
和之间有几个区别_beginthreadex()
。 _beginthreadex()
表现得更像CreateThread()
(在参数和行为方式上)。
As Drew Hallmentions, if you're using the C/C++ runtime, you must use _beginthread()
/_beginthreadex()
instead of CreateThread()
so that the runtime has a chance to perform it's own thread initialization (setting up thread local storage, etc.).
正如Drew Hall提到的,如果您使用的是 C/C++ 运行时,则必须使用_beginthread()
/_beginthreadex()
而不是,CreateThread()
以便运行时有机会执行它自己的线程初始化(设置线程本地存储等)。
In practice, this means that CreateThread()
should pretty much never be used directly by your code.
在实践中,这意味着CreateThread()
您的代码几乎不应该直接使用它。
The MSDN documents for _beginthread()
/_beginthreadex()
have quite a bit of detail on the differences - one of the more important is that since the thread handle for a thread created by _beginthread()
gets closed automatically by the CRT when the thread exits, "if the thread generated by _beginthread exits quickly, the handle returned to the caller of _beginthread might be invalid or, worse, point to another thread".
_beginthread()
/的 MSDN 文档对_beginthreadex()
差异有相当多的细节 - 其中一个更重要的是,由于_beginthread()
由 _beginthread创建的线程的线程句柄在线程退出时由 CRT 自动关闭,“如果由 _beginthread 生成的线程退出很快,返回给 _beginthread 调用者的句柄可能无效,或者更糟糕的是,指向另一个线程”。
Here is what the comments for _beginthreadex()
in the CRT source have to say:
以下是_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).
UpdateJan 2013:
2013 年 1 月更新:
The CRT for VS 2012 has an additional bit of initialization performed in _beginthreadex()
: if the process is a "packaged app" (if something useful is returned from GetCurrentPackageId()
) the runtime will initialize the MTA on the newly created thread.
VS 2012 的 CRT 在 中执行了额外的初始化_beginthreadex()
:如果进程是“打包的应用程序”(如果从 中返回有用的东西GetCurrentPackageId()
),则运行时将在新创建的线程上初始化 MTA。
回答by MSN
In general, the correct thing to do is to call _beginthread()/_endthread()
(or the ex()
variants). However, if you use the CRT as a .dll, the CRT state will be properly initialized and destroyed as the CRT's DllMain
will be called with DLL_THREAD_ATTACH
and DLL_THREAD_DETACH
when calling CreateThread()
and ExitThread()
or returning, respectively.
一般来说,正确的做法是调用_beginthread()/_endthread()
(或ex()
变体)。但是,如果您使用CRT作为一个.dll,在CRT状态将被正确的初始化和销毁CRT的DllMain
将被用DLL_THREAD_ATTACH
和DLL_THREAD_DETACH
打电话时CreateThread()
和ExitThread()
或分别返回。
The DllMain
code for the CRT can be found in the install directory for VS under VC\crt\src\crtlib.c.
DllMain
CRT的代码可以在 VS 的安装目录 VC\crt\src\crtlib.c 下找到。
回答by Constantin
This is the code at the core of _beginthreadex
(see crt\src\threadex.c
):
这是_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;
}
The rest of _beginthreadex
initializes per-thread data structure for CRT.
其余部分_beginthreadex
为 CRT 初始化每线程数据结构。
The advantage of using _beginthread*
is that your CRT calls from thread will work correctly.
使用的好处_beginthread*
是您的 CRT 线程调用将正常工作。
回答by jarcher7
You should use _beginthread
or _beginthreadex
to allow the C runtime library to do it's own initialization of the thread. Only C/C++ programmers need to know this as they should now the rules of using their own development environment.
您应该使用_beginthread
或_beginthreadex
允许 C 运行时库执行它自己的线程初始化。只有 C/C++ 程序员需要知道这一点,因为他们现在应该了解使用自己的开发环境的规则。
If you use _beginthread
you do not need to call CloseHandle
as the RTL will do for you. This is why you cannot wait on the handle if you have used _beginthread
. Also _beginthread
leads to confusion if the thread function exits immediately (quickly) as the launching thread my be left holding an invalid thread handle to the thread it just launched.
如果你使用_beginthread
你不需要调用,CloseHandle
因为 RTL 会为你做。这就是为什么如果您使用了_beginthread
. 也_beginthread
导致混乱,如果线程函数立即退出(快速)作为启动线程我可以左手拿着无效的线程句柄,它刚刚推出的线程。
_beginthreadex
handles can be used for wait but also require an explicit call to CloseHandle
. This is part of what makes them safe for using with wait. There other issue to make it completely foolproof is to always start the thread suspended. Check for success, record handle etc. The resume thread. This is required to prevent a thread from terminating before the launching thread can record its handle.
_beginthreadex
句柄可用于等待,但也需要显式调用CloseHandle
. 这是使它们可以安全地与等待一起使用的部分原因。使其完全万无一失的另一个问题是始终启动挂起的线程。检查是否成功,记录句柄等。恢复线程。这是防止线程在启动线程可以记录其句柄之前终止所必需的。
Best practice is to use _beginthreadex
, start suspended then resume after recording handle, wait on handle is OK, CloseHandle
must be called.
最好的做法是使用_beginthreadex
,开始挂起然后在记录句柄后恢复,等待句柄就可以了,CloseHandle
必须调用。
回答by Jaywalker
CreateThread()
used to have memory leakswhen you use any CRT functions in your code. _beginthreadex()
has same parameters as CreateThread()
and it's more versatile than _beginthread()
. So I recommend you use _beginthreadex()
.
CreateThread()
当您在代码中使用任何 CRT 函数时,过去常常会出现内存泄漏。_beginthreadex()
具有相同的参数,CreateThread()
并且比_beginthread()
. 所以我建议你使用_beginthreadex()
.
回答by Michael Burr
Regarding your updated question: "I've also read in a couple of places that I can't call WaitForSingleObject()
if I used _beginthread()
, but if I call _endthread()
in the thread shouldn't that work?"
关于你更新的问题:“我也在几个地方读过,WaitForSingleObject()
如果我使用了_beginthread()
,我就无法调用,但是如果我调用_endthread()
线程,那不应该吗?”
In general, you can pass a thread handle to WaitForSingleObject()
(or other APIs that wait on object handles) to block until the thread has completed. But the thread handle created by _beginthread()
is closed when _endthread()
is called (which can be done explicitly or is done implicitly by the run time when the thread procedure returns).
通常,您可以将线程句柄传递给WaitForSingleObject()
(或其他等待对象句柄的 API)以阻塞直到线程完成。但是创建的线程句柄_beginthread()
在_endthread()
被调用时关闭(这可以显式完成,也可以在线程过程返回时由运行时隐式完成)。
The problem is called out in the documentation for WaitForSingleObject()
:
问题在以下文档中提到WaitForSingleObject()
:
If this handle is closed while the wait is still pending, the function's behavior is undefined.
如果此句柄在等待仍处于挂起状态时关闭,则函数的行为未定义。
回答by bobobobo
Looking at the function signatures, CreateThread
is almost identical to _beginthreadex
.
查看函数签名,CreateThread
几乎与_beginthreadex
.
_beginthread
, _beginthreadx
vs CreateThread
_beginthread
,_beginthreadx
对CreateThread
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
);
The remarks on heresay _beginthread
can use either __cdecl
or __clrcall
calling convention as start point, and _beginthreadex
can use either __stdcall
or __clrcall
for start point.
这里的注释说_beginthread
可以使用__cdecl
或__clrcall
调用约定作为起点,也_beginthreadex
可以使用__stdcall
或__clrcall
为起点。
I think any comments people made on memory leaks in CreateThread
are over a decade old and should probably be ignored.
我认为人们对内存泄漏所做的任何评论CreateThread
都有十多年的历史,应该被忽略。
Interestingly, both _beginthread*
functions actually call CreateThread
under the hood, in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src
on my machine.
有趣的是,这两个_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;
}
回答by bobobobo
beginthreadex
gives you a thread HANDLE
for use in WaitForSingleObject
and friends. beginthread
doesn't. Don't forget to CloseHandle()
when you are done. The real answer would be to use boost::thread
or soon C++09's thread class.
beginthreadex
给你一个线程HANDLE
供在WaitForSingleObject
和朋友使用。beginthread
没有。完成后不要忘记CloseHandle()
。真正的答案是使用boost::thread
或很快使用C++09 的线程类。
回答by Vishal
Compared to _beginthread
, with _beginthreadex
you can:
与 相比_beginthread
,_beginthreadex
您可以:
- Specify security attributes.
- Start a thread in suspended state.
- You can get the thread id which can be used with
OpenThread
. - The thread handle returned is guaranteed to be valid if the call was
successful. There for you need to close the handle with
CloseHandle
. - The thread handle returned can be used with synchronization APIs.
- 指定安全属性。
- 启动处于挂起状态的线程。
- 您可以获得可以与
OpenThread
. - 如果调用成功,则保证返回的线程句柄有效。因为你需要用 关闭手柄
CloseHandle
。 - 返回的线程句柄可用于同步 API。
The _beginthreadex
closely resembles CreateThread
, but the former is a CRT implementation and the latter a Windows API call. The documentation for CreateThreadcontains the following recommendation:
在_beginthreadex
酷似CreateThread
,但前者是CRT实现,而后者Windows API调用。CreateThread的文档包含以下建议:
A thread in an executable that calls the C run-time library (CRT) should use the
_beginthreadex
and_endthreadex
functions for thread management rather thanCreateThread
andExitThread
; this requires the use of the multi-threaded version of the CRT. If a thread created usingCreateThread
calls the CRT, the CRT may terminate the process in low-memory conditions.
调用 C 运行时库 (CRT) 的可执行文件中的线程应该使用
_beginthreadex
and_endthreadex
函数进行线程管理,而不是使用CreateThread
andExitThread
;这需要使用 CRT 的多线程版本。如果使用创建的线程CreateThread
调用 CRT,则 CRT 可能会在内存不足的情况下终止进程。