c++创建线程:CreateThread 和pthread_create和 _beginthreadex

 

CreateThread

在 Windows 中,您可以使用 CreateThread() 来创建线程,创建的线程在调用进程的虚拟地址空间中运行。 
HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes,     // SD
  SIZE_T dwStackSize,                           // initial stack size
  LPTHREAD_START_ROUTINE lpStartAddress,        // thread function
  LPVOID lpParameter,                           // thread argument
  DWORD dwCreationFlags,                        // creation option
  LPDWORD lpThreadId                            // thread identifier
);
lpThreadAttributes 是指向线程属性的指针,决定了线程句柄是否能由子进程继承。 需要include"thread.cpp"

// thread.cpp
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// The _beginthread(), _beginthreadex(), _endthread(), and _endthreadex().
//
// There are several key differences in behavior between _beginthread() and
// _beginthreadex():
//
//  * _beginthreadex() takes three additional parameters, which are passed on to
//    CreateThread():  a security descriptor for the new thread, the initial
//    thread state (running or asleep), and an optional out parameter to which
//    the thread id of the newly created thread will be stored.
//
//  * The procedure passed to _beginthread() must be __cdecl and has no return
//    code.  The routine passed to _beginthreadex() must be __stdcall and must
//    return a return code, which will be used as the thread exit code.
//    Likewise, _endthread() takes no parameter and always returns a thread exit
//    code of 0 if the thread exits without error, whereas _endthreadex() takes
//    an exit code.
//
//  * _endthread() calls CloseHandle() on the handle returned from CreateThread().
//    Note that this means that a caller should not use this handle, since it is
//    possible that the thread will have terminated and the handle will have been
//    closed by the time that _beginthread() returns.
//
//    _endthreadex() does not call CloseHandle() to close the handle:  the caller
//    of _beginthreadex() is required to close the handle.
//
//  * _beginthread() returns -1 on failure.  _beginthreadex() returns zero on
//    failure (just as CreateThread() does).
/ / thread.cpp

//

//微软公司版权所有。保留所有权利。

//

//使用_beginthread()、_beginthreadex()、_endthread()和_endthreadex()。

//

//在_beginthread()和。之间有几个关键的区别

/ / _beginthreadex ():

//

// * _beginthreadex()接受三个额外的参数,它们被传递给

// CreateThread():新线程(初始线程)的安全描述符

//线程状态(运行或休眠),以及一个可选的out参数

//将存储新创建线程的线程id。

//

// *传递给_beginthread()的过程必须是cdecl,没有返回值

/ /代码。传递给_beginthreadex()的例程必须是_stdcall和must

//返回一个返回码,它将被用作线程退出码。

同样,_endthread()不接受任何参数,并且总是返回一个线程出口

//如果线程没有错误退出,则为0,而_endthreadex()接受

//退出代码。

//

// * _endthread()在CreateThread()返回的句柄上调用CloseHandle()。

//注意,这意味着调用者不应该使用这个句柄,因为它是

//可能线程已经终止,句柄也已经结束

//在_beginthread()返回时关闭。

//

// _endthreadex()不调用CloseHandle()来关闭句柄:调用者

// of _beginthreadex()是关闭句柄所必需的。

//

// * _beginthread()在失败时返回-1。_beginthreadex()返回零

//失败(就像CreateThread()一样)。

   由于历史原因,所以C/C++运行库并不是为多线程应用程序而设计的,所以为了保证其中的某些变量和函数的安全,那么必须创建一个数据结构,并使之与使用了C/C++运行库函数的每个线程所关联。当在调用C/C++运行库函数时,那些函数必须读取主调自己的线程的数据块,从而避免印象其他线程。

       所以当编写C/C++代码时,请调用_beginthreadex,而不要使用CreateThread的大致原因就是如上所述。详细内容请继续往下读😀😺😃

       _beginthreadex的函数参数列表与CreateThread一样,但是参数名和类型有所不同。这是因为C/C++程序不应该对Windows系统的类型有任何的依赖。

       _beginthreadex也会返回新建线程的句柄,就像CreateThread一样。可以非常方便的替换自己程序中的CreateThread函数,但是数据类型不一样,所以还得添加一些类型转换即可。
————————————————
版权声明:本文为优快云博主「昨夜的秋天」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/foreveyking/article/details/78029328

_beginthreadex 

      附加:绝不调用_beginthread。因为,

1._beginthread参数较少,不能创建具有安全属性的线程,不能让线程立即挂起等。_endthread也是如此,其退出代码被硬编码为0。

_endthread还存在一个问题,就是在调用ExitThread前,会调用CloseHandle,向其传入新线程的句柄。举个例子,比如你使用了_beginthread创建了一个新的线程,在其之后使用CloseHandle关闭线程句柄。由于_beginthread会调用_endthread函数终止线程,而线程内核对象的初始化计数为2,在_endthread函数中,调用ExitThread前,会调用CloseHandle,也就是说会连续两次递减引用计数,这时引用计数为0,内核对象被系统销毁,再之后在调用CloseHandle关闭线程句柄时,这个传入的句柄是无效的,即CloseHandle函数的调用会以失败告终。

所以请用_beginthreadex代替_beginthread,_endthreadex代替_endthread。      _beginthreadex调用的是_endthreadex,_beginthread调用的是_endthread

_beginthreadex内部使的是CreateThread


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

 

pthread_create



Linux 使用 pthread 库调用 pthread_create() 来派生线程: 
int pthread_create (
                    pthread_t *thread_id, 
                    pthread_attr_t *threadAttr,
                    void * (*start_address)(void *), 
                    void * arg);
注意:在 Windows 中,受可用虚拟内存的限制,一个进程可以创建的线程数目是有限的。默认情况下,每个线程有一兆栈空间。因此,您最多可以创建 2,028 个线程。如果您减小默认栈大小,那么可以创建更多线程。在 Linux 中,使用 ULIMIT -a(limits for all users)可以获得每个用户可以创建的线程的最大数目,可以使用 ULIMIT -u 来修改它,不过只有在登录时才可以这样做。 /usr/Include/limit.h 和 ulimit.h 下的头文件定义了这些内容。您可以修改它们并重新编译内核,以使其永久生效。对于 POSIX 线程限制而言,local_lim.h 中定义的 THREAD_THREADS_MAX 宏定义了数目的上限。 

 

指定线程函数

CreateThread() 中的 lpStartAddress 参数是刚创建的线程要执行的函数的地址。 
pthread_create() 库调用的 start_address 参数是刚创建的线程要执行的函数的地址。 

传递给线程函数的参数

在 Windows 中,系统调用 CreateThread() 的参数 lpParameter 指定了要传递给刚创建的线程的参数。它指明了将要传递给新线程的数据条目的地址。 
在 Linux 中,库调用 pthread_create() 的参数 arg 指定了将要传递给新线程的参数。 

 

AfxBeginThread

 

MFC专用的创建线程

UINT  myproc(LPVOID  lParam)
{
    CITapTradeAPITestDlg *pWnd = (CITapTradeAPITestDlg *)lParam;         //将窗口指针赋给无类型指针  
    pWnd->KMeansSegment();                         //要执行的函数  
    return 1;
}

 


  AfxBeginThread(myproc, (LPVOID)this);//启动新的线程  

 

void CITapTradeAPITestDlg::KMeansSegment()
{}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值