Chapter4线程4.2内容1.概述2.多线程模型3.线程库4.隐式线程5.若干线程问题1、概述4.4线程线程(轻型进程lightweightprocess,LWP)是CPU使用的一个基本单元,包括线程ID程序计数器寄存器集栈空间TCB(ThreadControlBlock)传统的或重型进程(heavyweightprocess)等价于只有一个线程的任务4.5单个线程和多线程进程4.6Windows2000ProcessandThreadWindows2000进程和线程4.7线程和进程调度线程是调度的基本单位,同一进程中的线程切换不会引起进程切换并发线程可以提高系统的并发性资源进程拥有资源,是资源分配的基本单位,而线程则不拥有资源,但它可以访问创建它的进程所拥有的资源上下文切换线程的上下文切换的代价比进程小4.8提出动机很多现代引用程序有多线程的要求线程位于进程内一个进程内的多个任务能利用多个线程执行更新网页显示接受数据拼写检查执行相似任务服务器发送网页进程创建:重量级线程创建:轻量级简化代码增加效率4.9多线程服务器4.10响应度高资源共享经济性MP体系结构的运用线程优点4.11并发(Concurrency)和并行(Parallelism)单核系统并发:多核系统并行:2、多线程模型4.13用户线程由用户级线程库进行管理的线程内核看不到用户线程,线程的创建和调度在用户空间,不需要内核的干预例子-POSIXPthreads-Win32threads-Javathreads4.14内核线程内核支持,操作系统管理的线程例子WindowsXP/2000SolarisLinuxTru64UNIXMacOSX4.15多线程模型多对一模型一对一模型多对多模型4.16多对一多个用户级线程映射到一个内核线程多个线程不能并行运行在多个处理器上线程管理在用户态执行,因此是高效的,但一个线程的阻塞系统调用会导致整个进程的阻塞用于不支持内核线程的系统中例子:SolarisGreenThreadsGNUPortableThreads4.17一对一每个用户级线程映射到一个内核线程比多对一模型有更好的并发性允许多个线程并行运行在多个处理器上创建一个ULT需要创建一个KLT,效率较差例子Windows95/98/NT/XP/2000LinuxSolaris9andlaterOS/24.18多对多多个用户级线程映射为相等或小于数目的内核线程允许操作系统创建足够多的内核线程例子Solaris9以前的版本带有ThreadFiber开发包的WindowsNT/20004.19两级模型类似于M:M,只不过它允许一个用户线程绑定到内核线程例子IRIXHP-UXTru64UNIXSolaris8andearlier3、线程库4.21线程库为程序员提供了创建和管理线程的API类型用户级线程库内核级线程库主要线程库:Windows线程库:内核级Pthread线程库:用户级或内核级JAVA线程库:用户级4.22Windows线程1对1映射每个线程包括:线程id寄存器集合堆栈私有数据线程主要的数据结构:ETHREAD(executivethreadblock):执行线程块KTHREAD(kernelthreadblock):核心线程块TEB(threadenvironmentblock):线程环境块4.23Windows线程结构4.24线程创建HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,SIZE_TdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);lpStartAddress是指向线程函数的指标。函数名称没有限制,但是必须以下列形式声明:DWORDWINAPIThreadProc(PVOIDpParam);lpParameter为传递给ThreadProc的参数。这样主线程和从属线程就可以共享数据。4.25_beginthreadhThread=_beginthread(ThreadProc,uiStackSize,pParam);语法为:void__cdeclThreadProc(void*pParam);4.26编译环境4.27线程管理设置线程的优先级线程优先级=进程优先级+线程相对优先级BoolSetThreadPriority(HANDLEhPriority,intnPriority)每个线程都有挂起计数器(suspendcount),为0时线程被执行;大于0时调度器不去调度该线程DWORDSuspendThread(HANDLEhThread);DWORDResumeThread(HANDLEhThread);4.28线程管理线程等待DWORDWaitForSingleObject(HANDLEhObject,//等待的核心对象DWORDdwTimeout);//线程愿意等待的毫秒数(值为INFINITE时表示无限等待)DWORDWaitForMultipleObject(DWORDcObject,//检查核心对象的数目LPHANDLElpHandles,//指向这些对象的句柄的数组BOOLbWaitAll,//是否等待所有对象变成有信号DWORDdwTimeout);//线程愿意等待的时间(毫秒数)线程内终止线程VOIDExitThread(DWORDdwExitCode);线程外终止线程BOOLTerminateThread(HANDLEhThread,DWORDdwExitCode);4.29例子#includestdafx.h#includewindows.h#includeiostreamusingnamespacestd;DWORDWINAPIFunOne(LPVOIDparam){while(true){Sleep(1000);couthello!;}return0;}DWORDWINAPIFunTwo(LPVOIDparam){while(true){Sleep(1000);coutworld!;}return0;}4.30例子intmain(intargc,char*argv[]){intinput=0;HANDLEhand1=CreateThread(NULL,0,FunOne,(void*)&input,CREATE_SUSPENDED,NULL);HANDLEhand2=CreateThread(NULL,0,FunTwo,(void*)&input,CREATE_SUSPENDED,NULL);while(true){cininput;if(input==1){ResumeThread(hand1);ResumeThread(hand2);}else{SuspendThread(hand1);SuspendThread(hand2);}};TerminateThread(hand1,1);TerminateThread(hand2,1);return0;}4.31Linux线程Linux用“任务”这个术语,一般不用“线程”线程可以通过clone()系统调用创建clone()–类fork()4.32PthreadsAPOSIX标注(IEEE1003.1c),用于线程创建和同步提供了线程有关的API接口常用于UNIX类操作系统(Solaris,Linux,MacOSX)4.33POSIX线程库Pthreads使用fork()创建进程代价昂贵进程间通信方式较复杂操作系统在实现进程间的切换比线程切换更费时使用pthreads库创建线程创建进程比创建线程更快线程间的通信方式更容操作系统对线程的切换比对进程的切换更容易和快速4.34线程的创建#includepthread.hintpthread_create(pthread_t*thread,pthread_attr_t*attr,void*(*start_routine)(void*),void*arg);第一个参数为指向线程标识符的指针第二个参数用来设置线程属性第三个参数是线程运行函数的起始地址最后一个参数是运行函数的参数4.35一个简单例子#includestdio.h#includepthread.h#includestring.h#includesys/types.h#includeunistd.hpthread_tntid;void*thr_fn(void*arg){printids(newthread:);return((void*)0);}intmain(){interr;err=pthread_create(&ntid,NULL,thr_fn,NULL);if(err!=0){printf(can'tcreatethread:%s\n,strerror(err));return1;}sleep(1);return0;}gcc-omypthread-lpthreadmypthread.c4.36线程结束调用pthread_exit()结束线程执行voidpthread_exit(void*retval);使用pthread_cancel()函数终止其他线程的执行intpthread_cancel(pthread_tthread);向线程t发送取消请求,默认情况下线程thread自己调用pthread_exit(PTHREAD_CANCELED),4.37线程等待pthread_join()函数等待被创建的线程结束pthread_join()函数会挂起创建线程的线程的执行,直到等待到想要等待的子线程函数原型:intpthread_join(pthread_tth,void**thread_return);4.38例子#includestdio.h#includestdlib.h#includeunistd.h#includepthread.h#defineTHREAD_NUMBER2intretval_hello1=2,retval_hello2=3;void*hello1(void*arg){char*hello_str=(char*)arg;sleep(1);printf(%s\n,hello_str);pthread_exit(&retval_hello1);}void*hello2(void*arg){char*hello_str=(char*)arg;sleep(2);printf(%s\n,hello_str);pthread_exit(&retval_hello2);}4.39intmain(intargc,char*argv[]){inti;intret_val,ret_val2;int*retval_hello[2];pthread_tpt[THREAD_NUMBER];constchar*arg[THREAD_NUMBER];arg[0]=helloworldfromthread1;arg[1]=helloworldfromthread2;printf(Begintocreatethreads...\n);ret_val1=pthread_create(&pt[0],NULL,hello1,(void*)arg[0]);ret_val2=pthread_create(&pt[1],NULL,hello2,(void*)arg[1]);例子4.40printf(Begintowaitforthreads...\n)