转自:https://my.oschina.net/zzw922cn/blog/493896
线程介绍
线程就是运行在一个进程上下文中的逻辑流,一般来说,程序是由每个进程中的单一线程来组成的。但是,我们实际上也可以编写一个进程里同时运行多个线程的程序,线程是由内核调度的,从进程间通信角度来看,一个给定进程内的所有线程共享同样的全局变量。每个线程具有独立的线程上下文,包括一个唯一的整数线程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