简体   繁体   English

function 的地址如何传递给 std::thread

[英]How address of a function will pass to the std::thread

I was debugging a multithreaded application that is using std::thread to run a function.我正在调试一个使用std::thread运行 function 的多线程应用程序。 I reach to the following code when debugging.调试时我达到以下代码。

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);
}

But I couldn't understand how address of the function passed to the CreateThread API.但我不明白 function 的地址如何传递给CreateThread API。 Why is it using thread_start<_beginthreadex_proc_type, true> , and how the address of a function will calculate by this statement in order to run by threads?为什么它使用thread_start<_beginthreadex_proc_type, true> ,以及 function 的地址将如何通过此语句计算以便由线程运行?

The code shown ( _beginthreadex function) is part of VC++ CRT (can be found in, eg显示的代码( _beginthreadex函数)是 VC++ CRT 的一部分(可以在例如
C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\startup\thread.cpp ). C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\startup\thread.cpp )。

An instance of unique_thread_parameter is a structure that holds the thread procedure pointer, the context argument, and thread and module HANDLE s: 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 creates such an instance: 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 is a template function that invokes the thread procedure: thread_start是调用线程过程的模板 function:

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;
}

It essentially calls invoke_thread_procedure , which just invokes procedure , passing in context :它本质上调用invoke_thread_procedure ,它只是调用procedure ,传入context

static __forceinline unsigned int invoke_thread_procedure(
    _beginthreadex_proc_type const procedure,
    void*                    const context
    ) throw()
{
    return procedure(context);
}

The code around the calls does some bookkeeping to keep the CRT consistent, for example it automatically cleans up the thread upon exit ( _endthreadex ).调用周围的代码会进行一些记账以保持 CRT 一致,例如它会在退出时自动清理线程 ( _endthreadex )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM