详解_beginthreadex()创建线程

2022-07-19,,

目录
  • 一、使用_beginthreadex()             
  • 二、_beginthreadex()与代createthread()区别                                   

一、使用_beginthreadex()             

需要的头文件支持#include         // for _beginthread()
需要的设置:projectàsetting-->c/c++-->user run-time library 选择debug multithreaded 或者multithreaded。即使用: mtmtd

代码如下:     
 

#include <stdio.h>
#include <string>             // for stl string class
#include <windows.h>          // for handle
#include <process.h>          // for _beginthread()
using namespace std;

class threadx
{
private:
  int loopstart;
  int loopend;
  int dispfrequency;
public:
  string threadname;

  threadx( int startvalue, int endvalue, int frequency )
  {
    loopstart = startvalue;
    loopend = endvalue;
    dispfrequency = frequency;
  }

  static unsigned __stdcall threadstaticentrypoint(void * pthis)
  {
      threadx * pthx = (threadx*)pthis;   // the tricky cast
      pthx->threadentrypoint();           // now call the true entry-point-function
      return 1;                              // the thread exit code
  }

  void threadentrypoint()
  {
    for (int i = loopstart; i <= loopend; ++i)
    {
      if (i % dispfrequency == 0)
      {
          printf( "%s: i = %d\n", threadname.c_str(), i );
      }
    }
    printf( "%s thread terminating\n", threadname.c_str() );
  }
};


int main()
{
    threadx * o1 = new threadx( 0, 1, 2000 );

    handle   hth1;
    unsigned  uithread1id;

    hth1 = (handle)_beginthreadex( null,         // security
                                   0,            // stack size
                                   threadx::threadstaticentrypoint,
                                   o1,           // arg list
                                   create_suspended,  // so we can later call resumethread()
                                   &uithread1id );

    if ( hth1 == 0 )
        printf("failed to create thread 1\n");

    dword   dwexitcode;
    getexitcodethread( hth1, &dwexitcode );  // should be still_active = 0x00000103 = 259
    printf( "initial thread 1 exit code = %u\n", dwexitcode );

    o1->threadname = "t1";

    threadx * o2 = new threadx( -100000, 0, 2000 );

    handle   hth2;
    unsigned  uithread2id;

    hth2 = (handle)_beginthreadex( null,         // security
                                   0,            // stack size
                                   threadx::threadstaticentrypoint,
                                   o2,           // arg list
                                   create_suspended,  // so we can later call resumethread()
                                   &uithread2id );

    if ( hth2 == 0 )
        printf("failed to create thread 2\n");

    getexitcodethread( hth2, &dwexitcode );  // should be still_active = 0x00000103 = 259
    printf( "initial thread 2 exit code = %u\n", dwexitcode );

    o2->threadname = "t2";

    resumethread( hth1 );   // serves the purpose of jaeschke's t1->start()
    resumethread( hth2 );   

    waitforsingleobject( hth1, infinite );
    waitforsingleobject( hth2, infinite );

    getexitcodethread( hth1, &dwexitcode );
    printf( "thread 1 exited with code %u\n", dwexitcode );

    getexitcodethread( hth2, &dwexitcode );
    printf( "thread 2 exited with code %u\n", dwexitcode );

    closehandle( hth1 );
    closehandle( hth2 );

    delete o1;
    o1 = null;

    delete o2;
    o2 = null;

    printf("primary thread terminating.\n");
    return 0;
}

注意:

  • (1)如果你正在编写c/c++代码,决不应该调用createthread。相反,应该使用visualc++运行期库函数_beginthreadex,退出也应该使用_endthreadex。如果不使用microsoft的visualc++编译器,你的编译器供应商有它自己的createthread替代函数。不管这个替代函数是什么,你都必须使用。
  • (2)因为_beginthreadex_endthreadex是crt线程函数,所以必须注意编译选项runtimelibaray的选择,使用mt或mtd。[multithreaded , debug multithreaded]
  • (3)_beginthreadex函数的参数列表与createthread函数的参数列表是相同的,但是参数名和类型并不完全相同。这是因为microsoft的c/c++运行期库的开发小组认为,c/c++运行期函数不应该对windows数据类型有任何依赖。_beginthreadex函数也像createthread那样,返回新创建的线程的句柄。
  • (4)c++主线程的终止,同时也会终止所有主线程创建的子线程,不管子线程有没有执行完毕。所以上面的代码中如果不调用waitforsingleobject,则2个子线程t1和t2可能并没有执行完毕或根本没有执行。
  • (5)如果某线程挂起,然后有调用waitforsingleobject等待该线程,就会导致死锁。所以上面的代码如果不调用resumethread,则会死锁。

二、_beginthreadex()与代createthread()区别                                   

createthread是windows的api函数(sdk函数的标准形式,直截了当的创建方式,任何场合都可以使用),提供操作系统级别的创建线程的操作,且仅限于工作者线程。不调用mfc和rtl的函数时,可以用createthread,其它情况不要轻易。在使用的过程中要考虑到进程的同步与互斥的关系(防止死锁)。线程函数定义为:dword winapi _yourthreadfun(lpvoid pparameter)。但它没有考虑:

  • (1)c runtime中需要对多线程进行纪录和初始化,以保证c函数库工作正常(典型的例子是strtok函数)。
  • (2)mfc也需要知道新线程的创建,也需要做一些初始化工作(当然,如果没用mfc就没事了)。  

afxbeginthread:mfc中线程创建的mfc函数,首先创建了相应的cwinthread对象,然后调用cwinthread::createthread,   在cwinthread::createthread中,完成了对线程对象的初始化工作,然后,调用_beginthreadex(afxbeginthread相比较更为安全)创建线程。它简化了操作或让线程能够响应消息,即可用于界面线程,也可以用于工作者线程,但要注意不要在一个mfc程序中使用_beginthreadex()或createthread()。线程函数定义为:uint
_yourthreadfun(lpvoid pparam)

_beginthreadex:ms对c runtime库的扩展sdk函数,首先针对c runtime库做了一些初始化的工作,以保证c runtime库工作正常。然后,调用createthread真正创建线程。 仅使用runtime library时,可以用_begingthread。

  • 小节:实际上,这三个函数之间存在一定的调用关系,第一个纯粹一些,后两个完成自己相应的工作之后,调用前者实现线程的创建。其中createthread是由操作系统提供的接口,而afxbeginthread_beginthread则是编译器对它的封装。
  • 小节:用_beginthreadex()_endthreadex函数应该是最佳选择,且都是c run-time library中的函数,函数的参数和数据类型都是c run-time library中的类型,这样在启动线程时就不需要进行windows数据类型和c run-time library中的数据类型之间的转化,从而,减低了线程启动时的资源消耗和时间的消耗。但使用_beginthread,无法创建带有安全属性的新线程,无法创建暂停的线程,也无法获得 线程id,_endthread的情况类似,它不带参数,这意味这线程的退出代码必须硬编码为0。
  • 小节:mfc也是c++类库(只不过是microsoft的c++类库,不是标准的c++类库),在mfc中也封装了new和delete两中运算符,所以用到new和delete的地方不一定非要使用_beginthreadex() 函数,用其他两个函数都可以。

_beginthreadex_beginthread在回调入口函数之前进行一些线程相关的crt的初始化操作。
crt的函数库在线程出现之前就已经存在,所以原有的crt不能真正支持线程,
这也导致了许多crt的函数在多线程的情况下必须有特殊的支持,不能简单的使用createthread就ok。
 

补充一点:_beginthreadex()是针对crt的线程函数,在线程中若要用到crt的函数,最好用这个启动线程,如果不用这个会有内存泄漏。

到此这篇关于详解_beginthreadex()创建线程的文章就介绍到这了,更多相关_beginthreadex()创建线程内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

《详解_beginthreadex()创建线程.doc》

下载本文的Word格式文档,以方便收藏与打印。