《《并发服务器》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《并发服务器》PPT课件.ppt(58页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第五章 并发服务器并发服务器基础多进程服务器多线程服务器I/O多路复用服务器非阻塞socket信号驱动I/O5.1并发服务器基础(1)理解多客户问题服务器服务器客户客户客户客户客户客户客户客户客户客户客户客户客户客户客户客户连接到一个服务器上的多客户示意图连接到一个服务器上的多客户示意图服务器以并发方式为多客户提供服务服务器以并发方式为多客户提供服务5.1并发服务器基础(2)服务器分类服务器分类按连接类型按连接类型面向连接的服务器面向连接的服务器 采用采用TCP协议,可靠。不足之处是:每个连接需要相应的套协议,可靠。不足之处是:每个连接需要相应的套接字,服务器要管理这些套接字,占用系统资源;连
2、接需要建接字,服务器要管理这些套接字,占用系统资源;连接需要建立和关闭过程,影响传输效率和响应时间,增加服务器负担。立和关闭过程,影响传输效率和响应时间,增加服务器负担。无连接的服务器无连接的服务器 采用采用uCP协议,但效率高,占用较少系统资源,服务器不必协议,但效率高,占用较少系统资源,服务器不必管理连接套接字。缺点:不可靠,需要程序中实现相应机制。管理连接套接字。缺点:不可靠,需要程序中实现相应机制。按处理方式按处理方式重复性服务器:重复性服务器:每次只处理一个客户请求,当上一个客户请求每次只处理一个客户请求,当上一个客户请求处理完成后,才处理下一个请求,简单,效率低。处理完成后,才处理
3、下一个请求,简单,效率低。并发服务器:并发服务器:每次可处理多个客户请求,复杂,效率高。每次可处理多个客户请求,复杂,效率高。5.1并发服务器基础(3)重复性服务器重复性服务器实现:实现:使用使用setsockopt()的的SO_REUSEADDR选项实现选项实现典型代码:典型代码:int opt,len;len=sizeof(opt)opt=SO_REUSEADDR;setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,len);实例:实例:源程序名:源程序名:itrclient.cpp和和itrserver.cpp5.1并发服务器基础(4)功能:功能:l服务
4、器等候客户连接,连接显示信息,并循环接收来自客户服务器等候客户连接,连接显示信息,并循环接收来自客户的信息;收到后显示之,反转后发回客户,直到某客户端输的信息;收到后显示之,反转后发回客户,直到某客户端输入入“bye”关闭连接,就能等待下一客户请求。关闭连接,就能等待下一客户请求。l客户首先与服务器连接,接收键盘输入字符串,发给服务器,客户首先与服务器连接,接收键盘输入字符串,发给服务器,接收服务器发回信息并显示,循环,直到接收服务器发回信息并显示,循环,直到bye,关闭连接。,关闭连接。运行程序:运行程序:服务器:服务器:%itrserver received client message:
5、1234 客户客户1:%itrclient connected to server.输入输入:1234 输出输出:4321 (可以反复输入可以反复输入,均得到反序字符串均得到反序字符串,直到直到“bye”为为止止)思考:思考:客户客户2、客户、客户3同时运行该程序,结果如何?同时运行该程序,结果如何?5.1并发服务器基础(5)并发服务器与并发技术并发服务器与并发技术 进程进程 进程是程序的一次运行。多个进程可以执行相同的代码(如父子进程是程序的一次运行。多个进程可以执行相同的代码(如父子进程),支持并发;单进程),支持并发;单CPU采用分时系统使多个进程同时执行。采用分时系统使多个进程同时执行
6、。通过主进程和子进程实现并发,主进程只接收客户请求,子进程通过主进程和子进程实现并发,主进程只接收客户请求,子进程只与客户通信。只与客户通信。线程线程 与进程类似,也支持并发。同一进程中的线程共享相同的全程变与进程类似,也支持并发。同一进程中的线程共享相同的全程变量和系统分配给该进程的资源,线程间切换更快。量和系统分配给该进程的资源,线程间切换更快。进程是最小的进程是最小的资源分配单位,而线程是最小的调度单位资源分配单位,而线程是最小的调度单位。I/O多路复用多路复用 系统提供系统提供select()函数,在多个描述符中选择被击活的描述符进行函数,在多个描述符中选择被击活的描述符进行操作。如一
7、个服务器同时与多个客户端连接,就有多个操作。如一个服务器同时与多个客户端连接,就有多个TCP套接套接字描述符,采用时分多路复用技术实现进程或线程的并发处理。字描述符,采用时分多路复用技术实现进程或线程的并发处理。5.1并发服务器基础(6)三种并发服务器算法三种并发服务器算法(1)并发无连接服务器算法)并发无连接服务器算法 无连接服务,不需要等待每个已连接上的数据,不必采用并无连接服务,不需要等待每个已连接上的数据,不必采用并发技术也能有效处理多个用户,用多进程发技术也能有效处理多个用户,用多进程/线程需处理大量系线程需处理大量系统开销,因此无连接服务一般不采用并发技术。统开销,因此无连接服务一
8、般不采用并发技术。(2)并发面向连接服务器算法)并发面向连接服务器算法 通过主进程通过主进程/线程和子进程线程和子进程/线程实现并发,主进程只接收客线程实现并发,主进程只接收客户请求,子进程只与客户通信。户请求,子进程只与客户通信。(3)单进程)单进程/线程的并发服务器算法线程的并发服务器算法 进程进程/线程需要较多的系统开销,采用线程需要较多的系统开销,采用I/O多路复用实现处理多路复用实现处理多个客户连接,不必产生多个进程多个客户连接,不必产生多个进程/线程。线程。5.2多进程服务器(1)listenfd服务器connect()函数客户连接请求listenfdconnfd服务器connec
9、t()函数客户连接建立服务器(父进程)服务器 (子进程)listenfdconnfdconnect()函数客户连接建立listenfdconnfdfork()函数listenfdconnfdconnect()函数客户连接建立listenfdconnfd服务器(父进程)服务器(子进程)(a)调用accept()前(b)调用accept()后(c)调用fork()后(d)主服务器进程和子服务器进程实现并发连接请求父进程关闭连接套接字子进程关闭侦听套接字5.2多进程服务器(2)进程概念进程概念进程是程序在一个数据集上以并发方式运行的一次过程。进程是程序在一个数据集上以并发方式运行的一次过程。l进程是
10、程序的动态执行。进程是程序的动态执行。l有生存期。有生存期。l由程序、数据、进程控制块构成。由程序、数据、进程控制块构成。l一个进程可包括多个程序,一个程序也可对应多个进程。一个进程可包括多个程序,一个程序也可对应多个进程。l每个进程有唯一的进程标识符每个进程有唯一的进程标识符pid。l用用ps命令看当前系统运行的进程。命令看当前系统运行的进程。5.2多进程服务器(3)系统调用系统调用l创建进程创建进程fork()原型:原型:#include#include pid_t fork(void);功能:功能:创建一个新进程,父子进程共享代码段。创建一个新进程,父子进程共享代码段。返回值:返回值:子
11、进程中为子进程中为0,父进程中为子进程,父进程中为子进程ID,出错为出错为-1。注:注:用用getpid()可以获得当前进程标识符,用可以获得当前进程标识符,用getppid()可以获可以获得父进程标识符;通过分支语句控制父子进程执行不同代码得父进程标识符;通过分支语句控制父子进程执行不同代码(如如C/S模式中模式中)。典型代码:典型代码:pid_t pid;if(pid=fork()0)/*parent process*/else if(pid=0)/*child process*/;exit(0);else cout“fork error!n”;exit(0);系统中已经有太多的系统中已经
12、有太多的进程或某用户的进程进程或某用户的进程总数超过了系统限制总数超过了系统限制5.2多进程服务器(4)例例1:利用利用fork()系统调用创建子进程系统调用创建子进程pp1.cpp例例2:父子进程享用共同的代码父子进程享用共同的代码pp2.cpp说明说明:调用调用fork()后后,父进程父进程/子进程执行顺序不确定子进程执行顺序不确定程序程序pp1运行结果运行结果 程序程序pp2运行结果运行结果Just 1 process now.Calling fork()Im the child.Program end.Im the parent.Program end.pid0=294i=0 j=0
13、pid=297 ppid=295 (4)i=0 j=297 pid=295 ppid=294 (2)i=295 j=296 pid=294 ppid=197 (1)i=295 j=0 pid=296 ppid=294 (3)1-2942-2953-2964-297197i=fork()j=fork()j=fork()5.2多进程服务器(5)l终止进程终止进程exit()、wait()和和waitpid1.exit()原型:原型:#include void exit(int status);功能:功能:终止进程,常用于关闭子进程打开的描述符,并返回终止进程,常用于关闭子进程打开的描述符,并返回状
14、态,父进程用状态,父进程用wait()、waitpid()获得该状态。获得该状态。返回值:返回值:无无注:注:子进程中使用子进程中使用exit()不能完全释放子进程所占用的资源,不能完全释放子进程所占用的资源,进程控制块进程控制块PCB中还保留它的信息,子进程变为中还保留它的信息,子进程变为“僵尸僵尸”进程,进程,ps能看到这样的进程,直到父进程调用能看到这样的进程,直到父进程调用wait()后完后完全释放子进程资源。全释放子进程资源。5.2多进程服务器(多进程服务器(6)父进程可能先于子进程终止,子进程也可能先于父进程终止。父进程可能先于子进程终止,子进程也可能先于父进程终止。2.wait(
15、)原型:原型:#include#include pid_t wait(int*stat_loc);功能:功能:在有子进程终止时,系统使用中断信号在有子进程终止时,系统使用中断信号SIGCHLD通知父进通知父进程有子进程终止,此时才能调用程有子进程终止,此时才能调用wait()。wait()允许父进程取得允许父进程取得子进程的状态信息,并挂起,等待子进程终止。子进程的状态信息,并挂起,等待子进程终止。返回值:返回值:正常,返回子进程进程号,否则正常,返回子进程进程号,否则-1;同时;同时stat_loc返回返回子进程返值。子进程返值。典型代码:典型代码:pid_t pid;int child_s
16、tatus;if(pid=fork()0)/*parent process*/;wait(&child_status);else if(pid=0)/*child process*/;exit(0);else cout“fork error!n”;exit(0);5.2多进程服务器(多进程服务器(7)原型:原型:#include#include pid_t waitpid(pid_t pid,int*stat_loc,int options);功能:功能:允许父进程取得指定子进程的状态信息允许父进程取得指定子进程的状态信息,其中:其中:pid是所等待是所等待的子进程号,的子进程号,-1时表示第
17、一个子进程;时表示第一个子进程;options表示等待的方式,表示等待的方式,如如WNOHANG表示无子进程结束时返回表示无子进程结束时返回;当当pid=-1,options=0时时,等价于等价于wait()。返回值:返回值:正常,返回子进程号,否则正常,返回子进程号,否则-1;stat_loc返回子进程返值返回子进程返值注:注:若有若干客户同时关闭连接,这些服务进程的父进程同时收到若有若干客户同时关闭连接,这些服务进程的父进程同时收到若干若干SIGCHLD中断信号,由于系统对中断信号无队列设置,导中断信号,由于系统对中断信号无队列设置,导致某些中断信号被丢弃,仍产生致某些中断信号被丢弃,仍产
18、生“僵尸僵尸”进程。进程。waitpid()可以控可以控制无子进程结束时返回。制无子进程结束时返回。典型代码:典型代码:clear_child(int signo)int stat,pid;while(pid=waitpid(-1,&stat,WNOHANG)0)cout“child process“pid“cleaned,return“statn;5.2多进程服务器(8)多进程并发服务器多进程并发服务器l方法方法用前面所学方法在服务器和客户端建立连接。用前面所学方法在服务器和客户端建立连接。服务器调用服务器调用fork()产生子进程。产生子进程。若子进程,关闭监听套接字若子进程,关闭监听套接
19、字(保留连接套接字保留连接套接字),处理客户请求,最后关闭连接套接字,用处理客户请求,最后关闭连接套接字,用exit()退退出进程。出进程。若父进程,关闭连接套接字(保留监听套接字若父进程,关闭连接套接字(保留监听套接字,套套接字描述符的引用计数减接字描述符的引用计数减1),等待另一客户的连),等待另一客户的连接。接。5.2多进程服务器(9)典型代码典型代码#include#include#include#include main();listenfd=socket();bind(listenfd,);listen(listenfd,);while(1)connfd=accept();if(p
20、id=fork()0)/*parent process*/;close(connfd);continue;else if(pid=0)/*child process*/;close(listenfd);exit(0);else cout“fork errorn”;exit(0);5.2多进程服务器(10)实例实例1源程序名:源程序名:procserver.c和和procclient.c功能描述:功能描述:服务器等候客户连接请求,连接成功后显示客户地址,服务器等候客户连接请求,连接成功后显示客户地址,接收客户名字并显示,循环接收客户字符串并显示,反序处理接收客户名字并显示,循环接收客户字符串并显
21、示,反序处理后发回客户端,服务器可同时处理多客户请求。而客户端先与后发回客户端,服务器可同时处理多客户请求。而客户端先与服务器连接,接收键盘输入的客户名字发给服务器,循环接收服务器连接,接收键盘输入的客户名字发给服务器,循环接收用户输入的字符串发给服务器,接收服务器发回的信息并显示,用户输入的字符串发给服务器,接收服务器发回的信息并显示,直到直到D客户关闭连接并退出。客户关闭连接并退出。运行程序:运行程序:服务器:服务器:$procserver You got a connection from 127.0.0.1.clients name is client1.Received client
22、(client1)message:1234 You got a connection from 127.0.0.1.clients name is client2.Received client(client2)message:abcd5.2多进程服务器(11)客户客户1:$procclient Connected to server.Input name:client1 Input string to server:1234 Server Message:4321客户客户2:$procclient Connected to server.Input name:client2 Input st
23、ring to server:abcd Server Message:dcba5.2多进程服务器(12)实例2源程序名:源程序名:multi.h mulprosrv.cpp mulprocli.cpp功能描述:功能描述:服务器等候客户连接请求,连接成功后显示客户地址和服务器等候客户连接请求,连接成功后显示客户地址和端口号,循环接收客户的两个整数端口号,循环接收客户的两个整数,相加后发回客户端。服务器相加后发回客户端。服务器可同时处理多客户请求。可同时处理多客户请求。客户端首先与服务器连接,循环接收用户输入的两个整数发客户端首先与服务器连接,循环接收用户输入的两个整数发给服务器给服务器,接收服务
24、器发回的两数和的信息并显示,询问是否继接收服务器发回的两数和的信息并显示,询问是否继续续(1或或0),0返回。返回。运行程序:运行程序:服务器服务器:$./mulprosrv one client is request service from 127.0.0.1 at PORT 32769(客户客户1)in process 1231:12+23=35 in process 1231:6+8=14 one client is request service from 202.113.29.19 at PORT 32770(客户客户2)in process 2050:2+3=5 client 1
25、27.0.0.1 closed child process 1231 cleaned return 05.2多进程服务器(13)客户客户1:$./enter an interger:12 enter another interger:23 12+23=35 would you like to continue(1:continue,0:end):1 enter an interger:6 enter another interger:8 6+8=14 would you like to continue(1:continue,0:end):0客户客户2:$./.5.3多线程服务器(1)线程基础
26、线程基础 线程能提高代码响应和性能,线程由系统内核按时间片进行管线程能提高代码响应和性能,线程由系统内核按时间片进行管理,在单处理器系统中,系统内核使用时间分片模拟线程的并理,在单处理器系统中,系统内核使用时间分片模拟线程的并发执行,在多处理器系统中,如同多个进程,线程也可以并发发执行,在多处理器系统中,如同多个进程,线程也可以并发执行。执行。同一进程中的线程共享如下内容:同一进程中的线程共享如下内容:全局变量全局变量数据数据虚拟内存虚拟内存打开的文件描述符打开的文件描述符当前工作目录当前工作目录用户及用户组用户及用户组ID每个线程具有独立的:每个线程具有独立的:线程线程IDerrno变量变量
27、优先级优先级5.3多线程服务器(2)POSIX的多线程库的多线程库1.pthread_create()原型:原型:#include int pthread_create(pthread_t*thread,const pthread_attr_t*attr,void *(*start_func)(void*),void*arg);功能:功能:程序运行时系统产生主线程,该函数产生其它线程,其中程序运行时系统产生主线程,该函数产生其它线程,其中:thread:指向线程:指向线程ID的指针,的指针,pthread_t就是就是unsigned int。attr:指向线程属性的指针,:指向线程属性的指针,
28、NULL为默认值。为默认值。start_func:指向线程执行的函数(通用函数指针)。:指向线程执行的函数(通用函数指针)。arg:为函数:为函数start_func传递参数传递参数,若传递多个参数若传递多个参数,须封装在须封装在一个结构中。一个结构中。返回值:返回值:成功返回成功返回0,否则返回非零的错误代码。,否则返回非零的错误代码。注注:fork()创建的子进程与其父进程使用同一个执行点,而创建的子进程与其父进程使用同一个执行点,而pthread_create()中的参数中的参数start_func指明新线程要执行的函数指明新线程要执行的函数5.3多线程服务器(3)典型代码:典型代码:#
29、include pthread_t thread;struct ARG int fd;struct sockaddr_in addr;arg;void*start_routine(void*arg);void main()if(pthread_create(&thread,NULL,start_routine,(void*)&arg)exit(1);/pthread_create()返回非零返回非零,表明创建线程失败表明创建线程失败 5.3多线程服务器(4)2.pthread_exit()原型:原型:#include void pthread_exit(void*value_ptr);功能:功
30、能:终止当前线程,终止当前线程,若若value_ptr非空则指向线程退出状态。非空则指向线程退出状态。一般用法取一般用法取NULL。返回值:返回值:无,若在线程中调用无,若在线程中调用exit(),将终止该进程所有线程,将终止该进程所有线程.典型代码:典型代码:(常用在线程执行的函数中常用在线程执行的函数中)void*start_routine(void*arg)pthread_exit(NULL);5.3多线程服务器(5)多线程并发服务器多线程并发服务器l方法方法用前面所学方法在服务器和客户端建立连接用前面所学方法在服务器和客户端建立连接服务器调用服务器调用pthread_create()产
31、生新线程产生新线程若主线程,等待另一客户的连接请求若主线程,等待另一客户的连接请求若新线程,处理客户请求若新线程,处理客户请求l给新线程传递参数给新线程传递参数普通方法:使用公共变量传参普通方法:使用公共变量传参通过分配通过分配arg的空间传递参数的空间传递参数l注意注意编译时要和线程库编译时要和线程库libpthread.a或或libpthread.so相连接相连接,如如:g+thrserver.cpp o thrserver-lpthread静态链接库动态链接库5.3多线程服务器(6)1.普通方法普通方法 void*start_routine(void*arg);struct ARG in
32、t connfd;int other;void main()struct ARG arg;int listenfd,connfd;pthread_t thread;/*connfd=accept()*/arg.connfd=connfd;arg.other=5;if(pthread_create(&thread,NULL,start_routine,(void*)&arg)exit(1);void*start_routine(void*arg)struct ARG info;info.connfd=(struct ARG*)arg)-connfd;info.other=(struct ARG*
33、)arg)-other;close(info.connfd);pthread_exit(NULL);说明:说明:变量变量arg是所有线程共用的,传递的参数为指针,假设新线程是所有线程共用的,传递的参数为指针,假设新线程A正处理客户正处理客户A请求,主线程又接受另一客户请求,主线程又接受另一客户B的连接,主线的连接,主线程将修改变量程将修改变量arg内容,故只能处理一个客户,无法同时处理内容,故只能处理一个客户,无法同时处理多个客户(不安全)。多个客户(不安全)。5.3多线程服务器(7)5.3多线程服务器(8)2.通过动态分配通过动态分配arg空间传递参数空间传递参数 void*start_ro
34、utine(void*arg);struct ARG int connfd;int other;void main()int listenfd,connfd;ARG*arg;pthread_t thread;/*connfd=accept()*/arg=new ARG;arg-connfd=connfd;arg-other=5;if(pthread_create(&thread,NULL,start_routine,(void*)arg)exit(1);void*start_routine(void*arg)ARG info;info.connfd=(ARG*)arg)-connfd;info
35、.other=(ARG*)arg)-other;close(info.connfd);delete arg;pthread_exit(NULL);说明:说明:创建新线程前,为新线程动态分配存储创建新线程前,为新线程动态分配存储arg的空间,传递参的空间,传递参数给新线程,新线程使用后释放数给新线程,新线程使用后释放arg。5.3多线程服务器(9)5.3多线程服务器(10)实例实例1源程序名:源程序名:thrserver.cpp和和procclient.cpp(方法方法2传参传参)功能描述:功能描述:与与5.2中实例中实例1功能相同功能相同编译过程:编译过程:$g+thrserver.cpp o
36、 thrserver-lpthread运行程序:运行程序:服务器:服务器:$thrserver You got a connection from 127.0.0.1.clients name is wen.Received client(wen)message:1234 You got a connection from 127.0.0.1.clients name is zhang.Received client(zhang)message:abcd客户客户1:$procclient Connected to server.Input name:wen Input string to se
37、rver:1234 Server Message:4321客户客户2:$procclient 5.3多线程服务器(11)实例实例2源程序名源程序名:multhrsrv.cpp和和mulprocli.cpp(方法方法1传参传参)功能描述功能描述:与与5.2实例实例2中功能相同,所不同的是服务器采用多线程中功能相同,所不同的是服务器采用多线程服务器提供并发服务。服务器提供并发服务。运行程序运行程序:服务器服务器:$./multhrsrv Process Idis 423 one client is request service from 127.0.0.1 at PORT 32769(客户客户1
38、)thread 1231 will process the request in thread 1231:12+23=35 in thread 1231:6+8=14 one client is request service from 127.0.0.1 at PORT 32770(客户客户2)thread 2050 will process the request in thread 2050:2+3=5 client 127.0.0.1 closed and thread 1231 TERMINATE client 127.0.0.1 closed and thread 2050 TER
39、MINATE5.3多线程服务器(12)线程安全线程安全由于同一进程中的所有线程共享相同的存储空间,如果多个线由于同一进程中的所有线程共享相同的存储空间,如果多个线程修改相同的内存区域可能会出现错误,这就是线程安全问题。程修改相同的内存区域可能会出现错误,这就是线程安全问题。实例实例3:源程序名:源程序名:thrserver1.cpp和和procclient.cpp功能描述:功能描述:修改修改4.3中实例中实例1,增加一个函数,增加一个函数savedata(),希望将,希望将每个线程接收的所有信息保存,线程终止时显示,每个线程接收的所有信息保存,线程终止时显示,但结果与想但结果与想象不符象不符。
40、原因是调用了非线程安全的函数。原因是调用了非线程安全的函数savedata(),该函数,该函数中包含了一个静态变量(多线程共享变量)中包含了一个静态变量(多线程共享变量)结论:结论:在多线程环境中应避免使用静态变量,而采用线程专用数在多线程环境中应避免使用静态变量,而采用线程专用数据(据(TSD)取代静态变量,它是线程私有的,是定义线程私有)取代静态变量,它是线程私有的,是定义线程私有数据的唯一方法。数据的唯一方法。5.3多线程服务器(12)运行程序运行程序:服务器服务器:$./thrserver1You got a connect from 127.0.0.1.clients name is
41、 wen.Received client(wen)message:1234You got a connect from 127.0.0.1.clients name is zhang.Received client(zhang)message:abcReceived client(wen)message:5678Client(wen)closed connection.users data:1234Received client(zhang)message:defClient(zhang)closed connection.users data:客户客户1:$procclientConnect
42、ed to server.Input name:wenInput string to server:1234 /依次输入依次输入1234、5678和和byeServer Message:4321客户客户2:$procclient 127.0.0.1 /依次输入依次输入abc、def和和bye5.3多线程服务器(13)与与TSD有关的函数有关的函数l pthread_key_create()原型:原型:#include int pthread_key_create(pthread_key_t*key,void(*destructor)(void*value);功能:功能:在进程内部分配一个标志在
43、进程内部分配一个标志TSD(线程专用数据线程专用数据)的关键字,的关键字,创建进程时为创建进程时为NULL,每个线程可以为关键字绑定一个值,该,每个线程可以为关键字绑定一个值,该值对绑定的线程是唯一的值对绑定的线程是唯一的(创建线程时为创建线程时为NULL),一般创建第,一般创建第一个新线程时使用。其中:一个新线程时使用。其中:key:指向创建的关键字。:指向创建的关键字。destructor:为析构函数,若它非空,:为析构函数,若它非空,key也非空,则线程退也非空,则线程退出时调用析构函数。出时调用析构函数。返回值:返回值:正常返回正常返回0,否则返回错误码。,否则返回错误码。5.3多线程
44、服务器(14)lpthread_setspecific()原型:原型:#include int pthread_setspecific(pthread_key_t*key,void*value)功能:功能:为为TSD关键字绑定一个与本线程相关的值。其中关键字绑定一个与本线程相关的值。其中value为为相关值。相关值。返回值:返回值:正常返回正常返回0,否则返回错误码。,否则返回错误码。l pthread_getspecific()原型:原型:#include void*pthread_getspecific(pthread_key_t*key)功能:功能:获得与调用线程相关的关键字所绑定的值。
45、获得与调用线程相关的关键字所绑定的值。返回值:返回值:正常返回与调用线程相关的关键字所绑定的值,若未正常返回与调用线程相关的关键字所绑定的值,若未绑定返回绑定返回NULL。5.3多线程服务器(15)典型代码典型代码:(某线程处理函数中某线程处理函数中)pthread_key_t key;pthread_key_create(&key,destructor);struct DATA int a;DATA *data;if(data=(DATA*)pthread_getspecific(key)=NULL)data=new DATA;pthread_setspecific(key,data);da
46、ta-a=5;5.3多线程服务器(16)lpthread_once()原型:原型:#include void*pthread_once(pthread_once_t*once_control,void(*init_routine)(void);功能:功能:初始化动态包,当设置为初始化动态包,当设置为PTHREAD_ONCE_INIT时,时,所指向的函数在同一进程中只被调用一次。其中:所指向的函数在同一进程中只被调用一次。其中:once_control=PTHREAD_ONCE_INIT init_routine:初始化时所指向的函数。:初始化时所指向的函数。返回值:返回值:正常返回正常返回0,
47、否则错误码。,否则错误码。5.3多线程服务器(17)典型代码:典型代码:static pthread_key_t key;static pthread_once_t once=PTHREAD_ONCE_INIT;static void destructor(void*ptr)delete ptr;static void getkey_once()pthread_key_create(&key,destructor);void fun()/某处理线程函数某处理线程函数 struct DATA int a;DATA *data;pthread_once(&once,getkey_once);if(
48、data=(DATA*)pthread_getspecific(key)=NULL)data=new DATA;pthread_setspecific(key,data);data-a=5;5.3多线程服务器(18)实例实例4:源程序名:源程序名:thrserver2.cpp和和procclient.cpp功能描述:功能描述:修改修改4.3中实例中实例3,采用,采用线程专用数据线程专用数据(TSD)取代)取代静态变量实现了实例静态变量实现了实例3希望实现的功能。希望实现的功能。实例实例5:源程序名:源程序名:thrserver3.cpp和和procclient.cpp功能描述:功能描述:修改修
49、改4.3中实例中实例3,另一种常用的方法是通过使用,另一种常用的方法是通过使用函函数的参变量数的参变量取代静态变量,但需要改变函数的原型以增加相取代静态变量,但需要改变函数的原型以增加相应的参变量,同样实现了实例应的参变量,同样实现了实例4的功能(自己看)。的功能(自己看)。5.4 I/O多路复用服务器(1)多路复用的基本原理多路复用的基本原理l当服务器同时处理两个输入流时(如当服务器同时处理两个输入流时(如stdio和和socket),常常使进程进入阻塞状态。即如果在输入流常常使进程进入阻塞状态。即如果在输入流A中阻塞,中阻塞,则无法处理输入流则无法处理输入流B中到达的数据,反之亦然。中到达
50、的数据,反之亦然。l生活中的例子:一个人需分别在两个不同车站接两个人,生活中的例子:一个人需分别在两个不同车站接两个人,若先去若先去A站接人,站接人,A站人没到,等待,直到接到站人没到,等待,直到接到A站人再站人再去去B站接另一人,此时站接另一人,此时B站人已等候多时,效率低。站人已等候多时,效率低。解决办法:谁先到就给接站的人打电话,然后接人。解决办法:谁先到就给接站的人打电话,然后接人。l这种思想就是多路复用的原理。这种思想就是多路复用的原理。5.4 I/O多路复用服务器(2)实现机制实现机制 服务器采用服务器采用I/O多路复用技术,由系统内核缓冲多路复用技术,由系统内核缓冲I/O数据,当