gpt4 book ai didi

c++ - 函数的地址如何传递给 std::thread

转载 作者:行者123 更新时间:2023-12-03 13:18:33 25 4
gpt4 key购买 nike

我正在调试一个使用 std::thread 的多线程应用程序。运行一个函数。调试时我达到以下代码。

extern "C" uintptr_t __cdecl _beginthreadex(
void* const security_descriptor,
unsigned int const stack_size,
_beginthreadex_proc_type const procedure,
void* const context,
unsigned int const creation_flags,
unsigned int* const thread_id_result
)
{
_VALIDATE_RETURN(procedure != nullptr, EINVAL, 0);

unique_thread_parameter parameter(create_thread_parameter(procedure, context));
if (!parameter)
{
return 0;
}

DWORD thread_id;
HANDLE const thread_handle = CreateThread(
reinterpret_cast<LPSECURITY_ATTRIBUTES>(security_descriptor),
stack_size,
thread_start<_beginthreadex_proc_type, true>,
parameter.get(),
creation_flags,
&thread_id);

if (!thread_handle)
{
__acrt_errno_map_os_error(GetLastError());
return 0;
}

if (thread_id_result)
{
*thread_id_result = thread_id;
}

// If we successfully created the thread, the thread now owns its parameter:
parameter.detach();

return reinterpret_cast<uintptr_t>(thread_handle);
}
但我无法理解函数的地址是如何传递给 CreateThread 的。 API。为什么使用 thread_start<_beginthreadex_proc_type, true> ,以及如何通过该语句计算函数的地址以便由线程运行?

最佳答案

显示的代码( _beginthreadex 函数)是 VC++ CRT 的一部分(可以在例如C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\startup\thread.cpp )。unique_thread_parameter 的一个实例是一个持有线程 procedure 的结构指针,context参数、线程和模块 HANDLE年代:

// corecrt_internal.h
typedef struct __acrt_thread_parameter
{
// The thread procedure and context argument
void* _procedure;
void* _context;

// The handle for the newly created thread. This is initialized only from
// _beginthread (not _beginthreadex). When a thread created via _beginthread
// exits, it frees this handle.
HANDLE _thread_handle;

// The handle for the module in which the user's thread procedure is defined.
// This may be null if the handle could not be obtained. This handle enables
// us to bump the reference count of the user's module, to ensure that the
// module will not be unloaded while the thread is executing. When the thread
// exits, it frees this handle.
HMODULE _module_handle;

// This flag is true if RoInitialized was called on the thread to initialize
// it into the MTA.
bool _initialized_apartment;
} __acrt_thread_parameter;

// thread.cpp
using unique_thread_parameter = __crt_unique_heap_ptr<
__acrt_thread_parameter,
thread_parameter_free_policy>;
create_thread_parameter创建这样一个实例:
static __acrt_thread_parameter* __cdecl create_thread_parameter(
void* const procedure,
void* const context
) throw()
{
unique_thread_parameter parameter(_calloc_crt_t(__acrt_thread_parameter, 1).detach());
if (!parameter)
{
return nullptr;
}

parameter.get()->_procedure = procedure;
parameter.get()->_context = context;

// Attempt to bump the reference count of the module in which the user's
// thread procedure is defined, to ensure that the module will stay loaded
// as long as the thread is executing. We will release this HMDOULE when
// the thread procedure returns or _endthreadex is called.
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
reinterpret_cast<LPCWSTR>(procedure),
&parameter.get()->_module_handle);

return parameter.detach();
}
thread_start是调用线程过程的模板函数:
template <typename ThreadProcedure>
static unsigned long WINAPI thread_start(void* const parameter) throw()
{
if (!parameter)
{
ExitThread(GetLastError());
}

__acrt_thread_parameter* const context = static_cast<__acrt_thread_parameter*>(parameter);

__acrt_getptd()->_beginthread_context = context;

if (__acrt_get_begin_thread_init_policy() == begin_thread_init_policy_ro_initialize)
{
context->_initialized_apartment = __acrt_RoInitialize(RO_INIT_MULTITHREADED) == S_OK;
}

__try
{
ThreadProcedure const procedure = reinterpret_cast<ThreadProcedure>(context->_procedure);

_endthreadex(invoke_thread_procedure(procedure, context->_context));
}
__except (_seh_filter_exe(GetExceptionCode(), GetExceptionInformation()))
{
// Execution should never reach here:
_exit(GetExceptionCode());
}

// This return statement will never be reached. All execution paths result
// in the thread or process exiting.
return 0;
}
它本质上调用 invoke_thread_procedure ,它只是调用 procedure , 传入 context :
static __forceinline unsigned int invoke_thread_procedure(
_beginthreadex_proc_type const procedure,
void* const context
) throw()
{
return procedure(context);
}
调用周围的代码会做一些簿记以保持 CRT 的一致性,例如
退出时自动清理线程( _endthreadex )。

关于c++ - 函数的地址如何传递给 std::thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63500919/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com