目录
四、线程创建函数_beginthread()和_beginthreadex()
当从一个进程切换到另一个进程时,需要保护当前进程的状态(主要是虚拟内存映像,文件描述符,寄存器内容等),并恢复将要运行的进程的状态,这不仅消耗CPU的执行时间,还要占用较多的存储空间。
线程是进程内部的一个执行单元。它只是简单地扩展了进程切换的概念,它从进程间的切换转变成了同一个进程内的函数间的切换。
为了减少进程切换时的时空开销,使操作系统具有更好的并发性,人们在操作系统中又引入了线程的概念。
① 同一个进程中函数间的切换相对于进程来说所需的开销要小的多,它只需要保存少数几个寄存器、一个堆栈指针以及程序计数器等少量内容。
② 线程实现了进程内的并发性。在支持线程的操作系统中,一个进程内至少有一个线程,称为主线程,它无需由用户去主动创建,是由系统自动创建的。系统创建好进程后,实际上就启动执行了该进程的主线程。
③进程中除主线程外还可以有多个子个线程。子线程是用户根据需要创建的。
多个线程之间可以并发执行(包括主线程和各级子线程),一个线程可以创建和撤消另一个线程。
由于线程之间的相互制约,致使线程在运行中呈现出间断性。
线程也有就绪、阻塞和运行三种基本状态。
① 同一进程中的多线程通常各自完成不同的工作,可以实现并行处理,避免了某项任务长时间占用CPU时间。
比如:一个线程负责通过网络收发数据,另一个线程完成所需的计算工作,第三个线程来做文件输入输出,当其中一个由于某种原因阻塞后(比如通过网络收发数据的线程等待对方发送数据),另外的线程仍然能执行而不被阻塞。
② 线程自己不独自拥有系统资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
③一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用该虚拟地址空间中的全局变量和系统资源,所以线程间的通讯非常方便。
1、创建线程时可以给线程传递一个LPVOID类型的参数,该参数为CreateThread()函数的第四个参数。
2、当参数为一个整型数据时,可将该整型数据强制转换为LPVOID类型,作为实参直接传递给线程函数。
3、当参数为一个字符串时,则创建线程时的实参传递既可以使用字符数组,也可以使用CString类。使用字符数组时,实参可直接使用字符数组名或指向字符数组的char* 指针;使用CString类时,可将指向CString对象的指针强制转换为LPVOID。
4、如果需要向线程传送多个数值时,由于线程函数的参数只有一个,所以需要先将它们封装在一个结构体变量中,然后将该变量的指针作为参数传给线程函数。
多线程运行时库与单线程运行时库有两个重大差别:
(1)类似errno的全局变量,每个线程单独设置一个;这样从每个线程中可以获取正确的错误信息。
(2)多线程库中的数据结构以同步机制加以保护。这样可以避免访问时候的冲突。
注:errno变量
为防止和正常的返回值混淆,C/C++语言的系统调用一般并不直接返回错误码,而是将错误码存入一个名为 errno 的全局变量中,errno 变量以及各种不同错误码的定义均在
文件中。 如果一个系统调用或库函数调用失败,可以通过读出 errno 的值来确定问题所在,推测程序出错的原因。
- unsigned long _beginthread
-
- (
- void( __cdecl *start_address )( void * ), //指向新线程调用的函数
- unsigned stack_size, //新线程堆栈的大小,可为0
- void *arglist //传递给线程的参数列表,可为NULL
- );
-
- unsigned long _beginthreadex
-
- (
- void *security, //指向SECURITY_ATTRIBUTES结构,用于决定返回句柄能否被继承
- unsigned stack_size,
- unsigned (__stdcall * pfnStartAddr) (void *) ,
- void *arglist,
- unsigned initflag, //若为0,线程立即执行,CREATE_SUSPENDED,则挂起
- unsigned *thrdaddr //存放线程ID
-
- );
-
在线程内部停止_beginthread()或_beginthreadex()创建的线程,可分别使用_endthread()函数和_endthreadex()函数,这两个函数的格式如下:
- void _endthread( void );
- void _endthreadex( unsigned retval );
- //参数retval为线程的退出代码。
如有错误,敬请指正。
您的收藏与点赞都是对我最大的鼓励和支持!