看了帖子《关于_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.不知道我讲的对不对,希望大家探讨!
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.不知道我讲的对不对,希望大家探讨!
解决方案 »
- select * from 表名 where 条件,“条件”的格式
- 谁能帮我破译一段编码
- 请教:将已存在MFC工程封装到DLL的问题,使用AFX_MANAGE_STATE(AfxGetStaticModuleState())仍无效
- 程序窗口标题的问题:“无标题”+程序名。如何能变成:”打开文件名”+程序名。
- 高分求DIB打印程序
- 使用ODBC访问数据库出现SQLconnetarrey()错误怎么办?
- HTML CleanUp 1.02
- 求MFC 开发的基于UDP多人聊天工具即UDP组播程序
- 获取键盘扫描码
- 请问return的问题?
- 麻烦各位大虾!请教在vc++环境下怎么建立系统日志文件
- 如何将RTF流数据写入RichEdit?
其实我觉得用CreateThread也挺好的。
_beginthreadex---------c运行时函数库
CreateThread-----------Kernel32.dll
每经过一层包装,都会产生属于自己的数据
库函数就在现场为调用线程分配一个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呢?)。
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
/***
*_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);
}
//观点:坚决不要用windows API的CreateThread?????????????????????楼主也未免太绝对了吧我现在就是用的CreateThread创建多个线程,程序运行很好
我想留待有心人啦!,不过我说说你的为什么可以,
原因一。我想你的线程,不会很多
原因二。一般线程都在construtor 产生,在程序退出才退出,所以不会有问题。我希望能做一个 不断产生线程和退出线程的循环,看有没有问题