线程就是运行在一个进程上下文中的逻辑流,通常来讲,程序是由每一个进程中的单一线程来组成的。可是,咱们实际上也能够编写一个进程里同时运行多个线程的程序,线程是由内核调度的,从进程间通讯角度来看,一个给定进程内的全部线程共享一样的全局变量。每一个线程具备独立的线程上下文,包括一个惟一的整数线程ID,栈,栈指针,程序计数器,通用目的寄存器和条件码。全部运行在一个进程中的线程共享该进程的整个虚拟地址空间。基于线程的逻辑流结合了基于进程和基于IO多路复用的流的特性,同进程同样,线程有内核自动调度,而且内核经过一个整数ID来识别线程,同基于多路IO复用同样,多个线程运行在单一进程的上下文之中,所以共享整个进程的虚拟地址空间,包括代码、数据、堆和共享库以及打开的文件。 服务器
每一个进程一开始都是由单一主线程构成的,在某一时刻,主线程建立一个对等线程,从这个时间点开始,两个线程就开始并发地运行。最后,由于主线程执行一个慢速系统调用,例如read函数或者sleep函数,线程就会被内核挂起,控制就会经过上下文切换传递到对等线程。对等线程就这样交替执行,以此类推。 多线程
//本程序是基于多线程的并发服务器 //为了不赋值语句在accept以后才完成的,那么对等线程中的局部变量connfd就获得下一次链接的描述符值,不幸的是,两个线程在同一个描述符上执行输入和输出 //为了不这种致命竞争,必须将每一个accept返回的已链接符分配到它本身的动态分配的存储器块 #include "csapp.h" void echo(int connfd) { int n; char buf[MAXLINE]; rio_t rio; rio_readinitb(&rio,connfd); //带缓冲的读取函数 while((n=rio_readlineb(&rio,buf,MAXLINE))>0) { //向链接符写入内容 printf("server received %d bytes \n",n); rio_writen(connfd,buf,n); } } void *thread(void *vargp); //线程函数声明 //主函数入口 int main(int argc,char **argv) { int listenfd,*connfd,port; //监听描述符,链接符,端口号 socklen_t clientlen=sizeof(struct sockaddr_in); //客户端地址长度 struct sockaddr_in clientaddr; //新建客户端地址 pthread_t tid; //线程id if(argc!=2) { fprintf(stderr,"usage :%s <port>\n",argv[0]); //提示执行格式 exit(0); //正常退出主程序,主进程 } port=atoi(argv[1]); //把端口号转成整型 listenfd=open_listenfd(port); //打开监听端口号 while(1) { //无限循环,等待接受请求 connfd=malloc(sizeof(int)); //动态分配内存给链接描述符,这是为了不两个线程在同一个描述符上输入输出,致使两个线程在同一个描述符上的不正当竞争 *connfd=accept(listenfd,(SA *)&clientaddr,&clientlen); //接受请求,已链接描述符 pthread_create(&tid,NULL,thread,connfd); //新建线程,而且传递参数connfdp进入线程 } } void *thread(void *vargp) { int connfd=*((int *)vargp);//接受参数 pthread_detach(pthread_self()); //分离线程,使得它不能被其余线程回收或杀死的,它的存储器资源在它终止时由系统自动释放 free(vargp); //释放参数存储空间 echo(connfd); //回应客户端 close(connfd); //关闭已链接描述符,这里不用在主线程中关闭,由于线程共享同一虚拟地址空间,此处关闭便可 return NULL;//线程结束 }
上面的多线程编译时,要加上-pthread参数,程序运行以下: 并发
zzw@zzw-ThinkPad-Edge-E430c:~$ telnet localhost 9999 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello hello
zzw@zzw-ThinkPad-Edge-E430c:~/doc_main/CProgram/Concurrency$ ./echoservert.o 9999 server received 7 bytes