- 不要再一个MFC程序中使用_beginthreadex()或者CreateThread().
- 如果你写一个多线程程序,而且没有使用MFC,那么你应该总是和多线程版本的C - Runtime library 连接,并且总是以_beginthreadex()和_endthreadex()取代CreateThread()和ExitThread(). _beginthreadex()的参数和CreateThread一样,并且承担适当的C runtime library 初始化工作。
- 只要你以_beginthreadex()取代CreateThread(), 你就可以在任何线程中安全的调用任何C runtime函数。
- 原先的C runtimelibrary是单线程版本的,没有考虑到多线程的需要,所以在多线程中使用时会引起race condition。多线程版本中,如errno之类的变量,现在变成了每个线程都各拥有一个,多线程中的数据结构都以同步机制加以保护。
- 如果以命令行或者从一个external makefile中执行visual c++编译器,你可以根据下列选项决定使用哪个版本的c runtime library
/ML Single-Threaded
/MT Multithreaded (static)
/MD Multithreaded dll
/MLd Debug Single-Threaded
/MTd Debug Multithreaded (static)
/MDd Debug Multithreaded dll - 为了保证多线程情况下的安全,runtime library 就必须为每个他启动的线程做一下登记,分别线程专属的内存作为线程的局部变量来使用。因此,_beginThreadex就包装了CreateThread,在其中做额外的登记工作。
uintptr_t _beginthreadex(
void *security, //相当于CreateThread中的security属性,NULL表默认
unsigned stack_size, //新线程的堆栈大小,单位字节, 对应的数据类型是DWORD
unsigned ( *start_address )( void * ), //线程启动函数
void *arglist, //线程的参数,对应win32的LPVOID
unsigned initflag, //启动的状态标志,对应win32的DWORD
unsigned *thrdaddr //新线程的ID
);
返回值:
线程的HANDLE,必须强制转换成类型为win32的handle后才能使用。如果函数失败,返回0,其原因被设定在errno和doserrno全局变量中。 - 绝对不要在一个以_beginthreadex启动的线程中调用ExitThread(),因为这样一来,C runtime library就没有机会释放"为该线程而配置的资源了"。而应该是用_endthreadex()
- 下面是一些一般性的规则,如果主线程之外的任何线程进行一下操作, 就应该使用多线程版本的C runtime library,并使用_beginthreadex和_encthreadex
在C程序中使用malloc和free,或者在c++程序中使用new 和delete
调用stdio.h或者io.h中声明的任何函数。
使用浮点变量或者浮点运算函数
调用任何一个使用了静态缓冲区的runtime函数,如asctime,strtok或者rand().
如果worker线程没有使用上述那些函数,那么单线程版本的runtime library以及CreateProcess都是安全的。 - 避免stdio.h,在许多情况下,舍弃C runtime library并不是困难,因为win32提供了许多关于文件处理,内存管理的函数。唯一担心的是如何在没有stdio.h的情况下进行屏幕输出。wsprintf函数可以代替sprintf。GetStdHandle函数可以获得stdin,stdout和stderr对应的win32句柄。
- 除非是多线程版本,否则C runtime library中的内存管理函数在多线程程序中是不安全的。
- 避免使用_beginthread().