导航:[首页]->[windows]->[_endthread和_endthreadex陷阱]

Msdn见这里这里

  • _beginthreadex是微软的C/C++运行时库函数,CreateThread是操作系统的函数。_beginthreadex通过调用CreateThread来实现的,但比CreateThread多做了许多工作。 注意:若要创建一个新线程,绝对不要使用CreateThread,而应使用_beginthreadex. Why?考虑标准C运行时库的一些变量和函数,如errno,这是一个全局变量。全局变量用于 多线程会出什么事,你一定知道的了。故必须存在一种机制,使得每个线程能够引用它自己的 errno变量,又不触及另一线程的errno变量._beginthreadex就为每个线程分配自己的 tiddata内存结构。该结构保存了许多像errno这样的变量和函数的值、地址(自己看去吧)。 通过线程局部存储将tiddata与线程联系起来。具体实现在Threadex.c中有。 结束线程使用函数__endthreadex函数,释放掉线程的tiddata数据块。
  • _beginthread returns -1L on an error. _beginthreadex returns 0 on an error(注意返回值别搞混了)
  • _endthread automatically closes the thread handle (whereas _endthreadex does not). Therefore, when using _beginthread and _endthread, do not explicitly close the thread handle by calling the Win32 CloseHandle API. (_endthread会自动关闭句柄,所以不要在显式的关闭之,也不要用它来Wait什么的,而_beginthreadex则需要明确地CloseHandle)
  • You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine passed as a parameter to _beginthread or _beginthreadex.(可以不用显式地去调用)
  • _endthread and _endthreadex cause C++ destructors pending in the thread not to be called.(直接调用会导致C++对象析构函数不被调用,当然若你没有显式或者隐式的C++对象,那就没问题)
  • It is safer to use _beginthreadex than _beginthread. 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. (尽量使用_beginthreadex)

Sample

    // crt_BEGTHRD.C
    // compile with: /MT /D "_X86_" /c
    // processor: x86
    #include <windows.h>
    #include <process.h>    /* _beginthread, _endthread */
    #include <stddef.h>
    #include <stdlib.h>
    #include <conio.h>

    void Bounce( void *ch );
    void CheckKey( void *dummy );

    /* GetRandom returns a random integer between min and max. */
    #define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

    BOOL repeat = TRUE;     /* Global repeat flag and video variable */
    HANDLE hStdOut;         /* Handle for console window */
    CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

    int main()
    {
        CHAR    ch = 'A';

        hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

        /* Get display screen's text row and column information. */
       GetConsoleScreenBufferInfo( hStdOut, &csbi );

        /* Launch CheckKey thread to check for terminating keystroke. */
        _beginthread( CheckKey, 0, NULL );

        /* Loop until CheckKey terminates program. */
        while( repeat )
        {
            /* On first loops, launch character threads. */
            _beginthread( Bounce, 0, (void *) (ch++)  );

            /* Wait one second between loops. */
            Sleep( 1000L );
        }
    }

    /* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
    void CheckKey( void *dummy )
    {
        _getch();
        repeat = 0;    /* _endthread implied */

    }

    /* Bounce - Thread to create and and control a colored letter that moves
     * around on the screen.
     *
     * Params: ch - the letter to be moved
     */
    void Bounce( void *ch )
    {
        /* Generate letter and color attribute from thread argument. */
        char    blankcell = 0x20;
        char    blockcell = (char) ch;
        BOOL    first = TRUE;
       COORD   oldcoord, newcoord;
       DWORD   result;


        /* Seed random number generator and get initial location. */
        srand( _threadid );
        newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
        newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
        while( repeat )
        {
            /* Pause between loops. */
            Sleep( 100L );

            /* Blank out our old position on the screen, and draw new letter. */
            if( first )
                first = FALSE;
            else
             WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
             WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );

            /* Increment the coordinate for next placement of the block. */
            oldcoord.X = newcoord.X;
            oldcoord.Y = newcoord.Y;
            newcoord.X += GetRandom( -1, 1 );
            newcoord.Y += GetRandom( -1, 1 );

            /* Correct placement (and beep) if about to go off the screen. */
            if( newcoord.X < 0 )
                newcoord.X = 1;
            else if( newcoord.X == csbi.dwSize.X )
                newcoord.X = csbi.dwSize.X - 2;
            else if( newcoord.Y < 0 )
                newcoord.Y = 1;
            else if( newcoord.Y == csbi.dwSize.Y )
                newcoord.Y = csbi.dwSize.Y - 2;

            /* If not at a screen border, continue, otherwise beep. */
            else
                continue;
            Beep( ((char) ch - 'A') * 100, 175 );
        }
        /* _endthread given to terminate */
        _endthread();
    }

    // crt_begthrdex.cpp
    // compile with: /MT
    #include <windows.h>
    #include <stdio.h>
    #include <process.h>

    unsigned Counter; 
    unsigned __stdcall SecondThreadFunc( void* pArguments )
    {
        printf( "In second thread...\n" );

        while ( Counter < 1000000 )
            Counter++;

        _endthreadex( 0 );
        return 0;
    } 

    int main()
    { 
        HANDLE hThread;
        unsigned threadID;

        printf( "Creating second thread...\n" );

        // Create the second thread.
        hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );

        // Wait until second thread terminates. If you comment out the line
        // below, Counter will not be correct because the thread has not
        // terminated, and Counter most likely has not been incremented to
        // 1000000 yet.
        WaitForSingleObject( hThread, INFINITE );
        printf( "Counter should be 1000000; it is-> %d\n", Counter );
        // Destroy the thread object.
        CloseHandle( hThread );
    }

参考: