c++ 多线程编程之创建新线程

多线程同步互斥,互斥是指某一资源一段时间内只允许一个访问者进行访问,同步是指在互斥的基础上,多个线程或进程按照一定顺序来运行 。


c++语言本身没有提供多线程机制,windows系统为我们提供了相关的API。

windowsAPI 提供了函数 CreateThread(),其基本过程为:

1.在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回
2.把线程退出码置为STILL_ACTIVE,把线程挂起计数置1
3.分配context结构
4.分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD
5.lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数
6.把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数


函数为

HANDLE WINAPI CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes,

SIZE_T dwStackSize,

LPTHREAD_START_ROUTINE lpStartAddress,

LPVOID lpParameter,

DWORD dwCreationFlags,

LPDWORD lpThreadId

);

第一个参数为线程内核安全属性,默认为NULL,

第二个参数为线程栈的空间大小,传入0表示使用默认大小1MB,而windows也会根据情况来动态延长堆栈大小。

第三个参数为 线程函数地址,使用DWORD WINAPI ThreadProc (LPVOID pParam) ; 来声明一个线程函数。(DWORD为双字即32bit,4字节,LPVOID为void指针,指向函数的参数)

第四个参数为传给线程函数的参数。

第五个函数 指定额外的标志来控制线程的创建,为0表示线程创建后立即调度,为CREATE_SUSPENDED表示线程创建后暂停运行,直到调用RESUMETHREAD(HANDLE );

第六个参数返回线程ID号,若为NULL,则不返回,为指针则将ID赋值个指针指向的地址。

多线程中常用的几个函数:

GetCurrentThreadId() 返回线程ID。

WaitForSingleObject

函数功能:等待函数 – 使线程进入等待状态,直到指定的内核对象被触发。

函数原形:

DWORD WIN API WaitForSingleObject(

HANDLE hHandle,

DWORD dwMilliseconds

);

函数说明:

第一个参数为要等待的内核对象。

第二个参数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入INFINITE表示无限等待。

因为线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以用WaitForSingleObject()来等待一个线程结束运行。

函数返回值:

在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED。

等待数组iphandles中所有线程句柄执行结束。

DWORD WaitForMultipleObjects(
DWORD nCount,//数组长度
const HANDLE* lpHandles,//数组指针
BOOL bWaitAll,//是否等待全部线程
DWORD dwMilliseconds//最大等待时间
);



不推荐使用CREATETHREAD的原因是c语言中为考虑多线程,如使用全局变量errno,则对于strerror()、strtok()、tmpnam()、gmtime()等函数会线程不安全,所以编译器建议使用这些函数的线程安全的新版本,或者使用线程安全的函数 _beginthreadex()。


_beginthreadex():

这个函数对于标准c库中进行的线程安全的解决办法是对于任意一个线程,配置一块专有的内存区来供c库中的函数使用。

这里发现,其实对于现在的编译器,已经不必使用这个函数了,因为不使用之前几个函数的线程安全型新函数就 给 编译错误,则,这个函数的线程安全的优势就没了,而且对于函数已经线程安全的情况下,这个函数新建一个内存区来保存信息明显是浪费空间和时间的选择。

这个函数大致参数与CreateThread相同,只是返回值类型为uintptr_t ,则对于新建一个线程并返回线程句柄需要强制转换为HANDLE类型,

线程函数的类型为 unsigned __stdcall fun(void * );

//第1个参数:安全属性,NULL为默认安全属性  
//第2个参数:指定线程堆栈的大小。如果为0,则线程堆栈大小和创建它的线程的相同。一般用0  
//第3个参数:指定线程函数的地址,也就是线程调用执行的函数地址(用函数名称即可,函数名称就表示地址)  
//第4个参数:传递给线程的参数的指针,可以通过传入对象的指针,在线程函数中再转化为对应类的指针  
//第5个参数:线程初始状态,0:立即运行;CREATE_SUSPEND:suspended(悬挂)  
//第6个参数:用于记录线程ID的地址  
uintptr_t _beginthreadex( // NATIVE CODE  
   void *security,  
   unsigned stack_size,  
   unsigned ( __stdcall *start_address )( void * ),  
   void *arglist,  
   unsigned initflag,  
   unsigned *thrdaddr   
);  



你可能感兴趣的:(c++ 多线程编程之创建新线程)