看了帖子《关于_beginthreadex、CreateThread、AfxBeginThread的选择》
http://expert.csdn.net/Expert/topic/2396/2396966.xml?temp=.9162104
--------------------------------------------------------------------
心中有些看法,不知对不对,希望探讨一下:
观点:坚决不要用windows API的CreateThread.
   只要用c/c++ 编程,vc++ IDE就一定要用_beginthreadx/ MFC(AfxBeginThread)
   因为标准C运行期库是1 9 7 0年问世的,它远远早于线程在任何应
用程序上的应用。运行期库的发明者没有考虑到将C运行期库用于多线程应用程序的问题。
考虑一下标准C运行期的全局变量e r r n o。有些函数在发生错误时设置该变量。
如果A thread错误时,线程刚好switch to 另外一个线程(B),而B thread 改变了errno,A 判断errno就是错误的,因此为了解决类似问题,c/C++ multiThread library, 要用一个struct(tiddata)来管理各个线程的errno等问题。
这就是在_beginthreadx 中有一句
   ptd = _calloc_crt(1, sizeof(struct tiddata))的用意。
同时这也是为什么不用API E x i t T h r e a d去delete thread的原因。
而是用 _endthreadx,它首先要delete 这个struct(tiddata)。至于AfxBeginThread,实际上它是call CWinThread类的CreateThread,注意我说的是
CWinThread::CreateThread,而不是Wnd 的API CreateThread, 其实CWinThread::CreateThread实际上也是call _beginthreadx.不知道我讲的对不对,希望大家探讨!

解决方案 »

  1.   


    其实我觉得用CreateThread也挺好的。
      

  2.   

    AfxBeginThread---------MFC
    _beginthreadex---------c运行时函数库
    CreateThread-----------Kernel32.dll
    每经过一层包装,都会产生属于自己的数据
      

  3.   

    也许你想知道,如果调用C r e a t e T h r e a d,而不是调用C / C + +运行期库的_ b e g i n t h r e a d e x来创建新线程,将会发生什么情况。当一个线程调用要求t i d d a t a结构的C / C + +运行期库函数时,将会发生下面的一些情况(大多数C / C + +运行期库函数都是线程安全函数,不需要该结构)。首先, C / C + +运行期库函数试图(通过调用T l s G e t Va l u e )获取线程的数据块的地址。如果返回N U L L作为t i d d a t a块的地址,调用线程就不拥有与该地址相关的t i d d a t a块。这时,C / C + +运行期
    库函数就在现场为调用线程分配一个t i d d a t a块,并对它进行初始化。然后该t i d d a t a块(通过T l s S e t Va l u e)与线程相关联。此时,只要线程在运行,该t i d d a t a将与线程待在一起。这时,C / C + +运行期库函数就可以使用线程的t i d d a t a块,而且将来被调用的所有C / C + +运行期函数也能使用t i d d a t a块。
    当然,这看来有些奇怪,因为线程运行时几乎没有任何障碍。不过,实际上还是存在一些
    问题。首先,如果线程使用C / C + +运行期库的s i g n a l函数,那么整个进程就会终止运行,因为结构化异常处理帧尚未准备好。第二,如果不是调用_ e n d t h r e a d e x来终止线程的运行,那么数据块就不会被撤消,内存泄漏就会出现(那么谁还为使用C r e a t e T h r e a d函数创建的线程来调用_ e n d t h r e a d e x呢?)。
      

  4.   

    MS的C运行库是为了兼容POSIX 的,这些也是建立在MS的操作系统内核上的!实际上_beginthread 到最后还是调用了内核的 CreateThread!!以下是反汇编代码
                     public __beginthread
    .text:7800A1AD __beginthread   proc near
    .text:7800A1AD 
    .text:7800A1AD arg_0           = dword ptr  0Ch
    .text:7800A1AD arg_4           = dword ptr  10h
    .text:7800A1AD arg_8           = dword ptr  14h
    .text:7800A1AD 
    .text:7800A1AD                 push    esi
    .text:7800A1AE                 push    edi
    .text:7800A1AF                 push    7Ch             ; size_t
    .text:7800A1B1                 push    1               ; size_t
    .text:7800A1B3                 xor     edi, edi
    .text:7800A1B5                 call    _calloc
    .text:7800A1BA                 mov     esi, eax
    .text:7800A1BC                 pop     ecx
    .text:7800A1BD                 test    esi, esi
    .text:7800A1BF                 pop     ecx
    .text:7800A1C0                 jz      short loc_7800A208
    .text:7800A1C2                 push    esi
    .text:7800A1C3                 call    __initptd
    .text:7800A1C8                 mov     eax, [esp+4+arg_0]
    .text:7800A1CC                 pop     ecx
    .text:7800A1CD                 push    esi
    .text:7800A1CE                 push    4
    .text:7800A1D0                 push    esi
    .text:7800A1D1                 push    offset sub_7800A224
    .text:7800A1D6                 push    [esp+10h+arg_4]
    .text:7800A1DA                 mov     [esi+48h], eax
    .text:7800A1DD                 mov     eax, [esp+14h+arg_8]
    .text:7800A1E1                 push    edi
    .text:7800A1E2                 mov     [esi+4Ch], eax
    .text:7800A1E5                 call    ds:__imp__CreateThread@24 ; __declspec(dllimport) CreateThread(x,x,x,x,x,x)
    .text:7800A1EB                 mov     edi, eax
    .text:7800A1ED                 test    edi, edi
    .text:7800A1EF                 mov     [esi+4], edi
    .text:7800A1F2                 jz      short loc_7800A200
    .text:7800A1F4                 push    edi
    .text:7800A1F5                 call    ds:__imp__ResumeThread@4 ; __declspec(dllimport) ResumeThread(x)
    .text:7800A1FB                 cmp     eax, 0FFFFFFFFh
    .text:7800A1FE                 jnz     short loc_7800A220
    .text:7800A200 
    .text:7800A200 loc_7800A200:                           ; CODE XREF: __beginthread+45j
    .text:7800A200                 call    ds:__imp__GetLastError@0 ; __declspec(dllimport) GetLastError()
    .text:7800A206                 mov     edi, eax
    .text:7800A208 
    .text:7800A208 loc_7800A208:                           ; CODE XREF: __beginthread+13j
    .text:7800A208                 push    esi             ; void *
    .text:7800A209                 call    _free
    .text:7800A20E                 test    edi, edi
    .text:7800A210                 pop     ecx
    .text:7800A211                 jz      short loc_7800A21A
    .text:7800A213                 push    edi
    .text:7800A214                 call    __dosmaperr
    .text:7800A219                 pop     ecx
    .text:7800A21A 
    .text:7800A21A loc_7800A21A:                           ; CODE XREF: __beginthread+64j
    .text:7800A21A                 or      eax, 0FFFFFFFFh
    .text:7800A21D 
    .text:7800A21D loc_7800A21D:                           ; CODE XREF: __beginthread+75j
    .text:7800A21D                 pop     edi
    .text:7800A21E                 pop     esi
    .text:7800A21F                 retn
    .text:7800A220 ;
    .text:7800A220 
    .text:7800A220 loc_7800A220:                           ; CODE XREF: __beginthread+51j
    .text:7800A220                 mov     eax, edi
    .text:7800A222                 jmp     short loc_7800A21D
    .text:7800A222 __beginthread   endp
      

  5.   

    只是C实现代码
    /***
    *_beginthread() - Create a child thread
    *
    *Purpose:
    *       Create a child thread.
    *
    *Entry:
    *       initialcode = pointer to thread's startup code address
    *       stacksize = size of stack
    *       argument = argument to be passed to new thread
    *
    *Exit:
    *       success = handle for new thread if successful
    *
    *       failure = (unsigned long) -1L in case of error, errno and _doserrno
    *                 are set
    *
    *Exceptions:
    *
    *******************************************************************************/unsigned long __cdecl _beginthread (
            void (__cdecl * initialcode) (void *),
            unsigned stacksize,
            void * argument
            )
    {
            _ptiddata ptd;                  /* pointer to per-thread data */
            unsigned long thdl;             /* thread handle */
            unsigned long errcode = 0L;     /* Return from GetLastError() */        /*
             * Allocate and initialize a per-thread data structure for the to-
             * be-created thread.
             */
            if ( (ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL )
                    goto error_return;        /*
             * Initialize the per-thread data
             */        _initptd(ptd);        ptd->_initaddr = (void *) initialcode;
            ptd->_initarg = argument;        /*
             * Create the new thread. Bring it up in a suspended state so that
             * the _thandle and _tid fields are filled in before execution
             * starts.
             */
            if ( (ptd->_thandle = thdl = (unsigned long)
                  CreateThread( NULL,
                                stacksize,
                                _threadstart,
                                (LPVOID)ptd,
                                CREATE_SUSPENDED,
                                (LPDWORD)&(ptd->_tid) ))
                 == 0L )
            {
                    errcode = GetLastError();
                    goto error_return;
            }        /*
             * Start the new thread executing
             */
            if ( ResumeThread( (HANDLE)thdl ) == (DWORD)(-1L) ) {
                    errcode = GetLastError();
                    goto error_return;
            }        /*
             * Good return
             */
            return(thdl);        /*
             * Error return
             */
    error_return:
            /*
             * Either ptd is NULL, or it points to the no-longer-necessary block
             * calloc-ed for the _tiddata struct which should now be freed up.
             */
            _free_crt(ptd);        /*
             * Map the error, if necessary.
             */
            if ( errcode != 0L )
                    _dosmaperr(errcode);        return((unsigned long)-1L);
    }
      

  6.   


    //观点:坚决不要用windows API的CreateThread?????????????????????楼主也未免太绝对了吧我现在就是用的CreateThread创建多个线程,程序运行很好
      

  7.   

    呵呵,我这个没有做测试(工作太忙)
    我想留待有心人啦!,不过我说说你的为什么可以,
    原因一。我想你的线程,不会很多
    原因二。一般线程都在construtor 产生,在程序退出才退出,所以不会有问题。我希望能做一个 不断产生线程和退出线程的循环,看有没有问题