线程作为程序执行的最小单位,一个进程中可以拥有多条线程,所有线程可以共享进程的内存区域,线程通常在运行时也需要一组寄存器、内存、栈等资源的支撑。
文章目录
多线程并发服务器说明server端client端pthread_creat()
说明
在使用线程模型开发服务器时需考虑以下问题: 1.调整进程内最大文件描述符上限 2.线程如有共享数据,考虑线程同步 3.服务于客户端线程退出时,退出处理。(退出值,分离态) 4.系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU
注:以下server端和client段的代码中的接口函数均采用错误封装处理后的函数(首字母大写),便于调试时定位错误出处,具体错误封装代码可参考以下博文:https://blog.csdn.net/weixin_42734533/article/details/123531214?spm=1001.2014.3001.5502
PS:若不考虑错误函数封装也可,只需将代码中的涉及的接口函数(如:Socket、Listen、Connect…)的首字母改成小写(如:socket、listen、connect…),程序运行时直接调用系统库中的函数,将不会调用错误函数封装中的函数。
#includeclient端#include #include #include #include #include #include //IP转换函数 #include //toupper函数头文件 #include #include #include #include #include #include //线程头文件 #include "wrap.h" // #define MAXLINE 800 #define INET_ADDRSTRLEN 16 #define SERV_PORT 6666 struct s_info{ //定义一个结构体,将客户端的地址与connfd进行捆绑 struct sockaddr_in cliaddr; int connfd; }; void *do_work(void* arg) { int n,i; struct s_info *ts=(struct s_info*)arg; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; while(1) { n=Read(ts->connfd,buf,MAXLINE); if(n==0) { printf("the other size has beens closedn"); break; } printf("Data from client is:%s",buf); for(i=0;i connfd,buf,MAXLINE); //写回客户端 memset(buf,0,n); } Close(ts->connfd); pthread_exit(0); } int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; char buf[MAXLINE]; char str[MAXLINE]; int i, n; pthread_t tid; //定义pthread_t型的变量 struct s_info ts[100]; //创建结构体数组,设置线程上限 i=0; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); Listen(listenfd, 20); printf("Accepting connections ...n"); cliaddr_len=sizeof(cliaddr); while(1) { connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); ts[i].cliaddr=cliaddr; ts[i].connfd=connfd; pthread_create(&tid,NULL,do_work,(void*)&ts[i]); //将ts[i]作为参数传递给子线程do_work()函数 pthread_detach(tid); //将线程设置成分离的,线程运行结束后会自动释放所有资源 i++; //起下一线程 } // return 0; pthread_exit(0); }
#includepthread_creat()#include #include #include #include #include #include "wrap.h" #define MAXLINE 80 #define SERV_PORT 6666 int main(int argc, char *argv[]) { struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd, n; sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while (fgets(buf, MAXLINE, stdin) != NULL) { Write(sockfd, buf, strlen(buf)); n = Read(sockfd, buf, MAXLINE); if (n == 0) { printf("the other side has been closed.n"); break; } else Write(STDOUT_FILENO, buf, n); } Close(sockfd); return 0; }
pthread_creat()函数创建线程
函数原型声明:
#includeint pthread_creat( pthread_t *restrict tidp, //新创建的线程ID指向的内存单元。 const pthread_attr_t *restrict attr, //线程属性,默认为NULL void *(*start_rtn)(void *), //新创建的线程从start_rtn函数的地址开 始运行,该函数的参数就是 void*类型的指针,也就是第四个参数【void *restrict arg】 void *restrict arg //默认为NULL。若上述函数需要参数,将参数放入结构 中并将地址作为arg传入。 )
pthread_detach()作用:线程分离
创建一个线程在运行结束后,存在一部分资源没有回收(退出状态码),所以需要调用pthread_join来等待线程运行结束,从而回收资源。
但是调用pthread_join(pthread_id)后,该线程没有运行结束,调用者会被阻塞。当主线程再创建子线程时,子线程被阻塞,影响使用。基于此,需要在子线程加入代码pthread_detach(pthread_self)或者主线程中调用pthread_detach(thread_id),这就将子线程的状态设置为detached(脱离的)即子线程运行结束后会自动释放所有资源
上述多线程程序在编译过程中会出现:【undefined reference to ‘pthread_create’】
原因在于:pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a,所以在使用pthread_create()创建线程,以及调用 pthread_atfork()函数建立fork处理程序时,需要链接该库。
解决:
在编译中要加 -lpthread参数
gcc thread.c -o thread -lpthread
thread.c为你些的源文件,不要忘了加上头文件#include
编译运行指令如下:
gcc server.c wrap.c -o server -lpthread



