第184页 第18章 多线程服务器端的实现
秋风
读过 TCP/IP网络编程
- 章节名:第18章 多线程服务器端的实现
- 页码:第184页
多进程模型的缺点: 1.创建进程、Context Switching开销大; 2.进程间通信,需要特殊IPC技术。 引自 第18章 多线程服务器端的实现 线程编程介绍:http://book.douban.com/annotation/34642229/ 线程安全函数:Linnux平台在定义非线程安全函数同时提供了具有相同功能额线程安全函数;线程安全函数后缀通常为_t Or 在编译程序时使用宏选项(-D_REENTRANT)。
/************************************************************************* > File Name: thread_test.c > Author: xjhznick > Mail: xjhznick@gmail.com > Created Time: 2015年04月03日 星期五 15时15分58秒 > Description: ************************************************************************/ #include<stdio.h> #include<pthread.h> #include<unistd.h> #include<stdlib.h> #define THREAD_NUM 100 void * thread_inc(void *arg); void * thread_dec(void *arg); long long num = 0; int main(int argc, char *argv[]) { pthread_t thread_id[THREAD_NUM]; int i; printf("sizeof(long long) = %lu\n", sizeof(long long)); for(i=0; i<THREAD_NUM; i++){ if(i%2){ pthread_create(&(thread_id[i]), NULL, thread_inc, NULL); }else{ pthread_create(&(thread_id[i]), NULL, thread_dec, NULL); } //pthread_join(thread_id[i], NULL); //The result is OK. } for(i=0; i<THREAD_NUM; i++){ pthread_join(thread_id[i], NULL); } printf("Result = %lld\n", num); return 0; } void *thread_inc(void *arg) { int i; for(i=0; i<50000000; i++){ num += 1; } return NULL; } void *thread_dec(void *arg) { int i; for(i=0; i<50000000; i++){ num -= 1; } return NULL; }$ gcc pthread_test.c -D_REENTRANT -lpthread $ ./a.out sizeof(long long) = 8 Result = -1437615 ------------------------------------------------------------------------------------------------------- 需要考虑进行同步的情况: 1.同时访问同一内存空间; 2.需要指定访问同一内存空间的线程执行顺序的情况 例如将生活中的厕所当作临界区对待,其使用规则与程序中互斥量(一个坑位) 信号量(n个坑位)访问临界区规则完全一样。
/************************************************************************* > File Name: thread_mutex_test.c > Author: xjhznick > Mail: xjhznick@gmail.com > Created Time: 2015年04月03日 星期五 15时45分58秒 > Description: ************************************************************************/ #include<stdio.h> #include<pthread.h> #include<unistd.h> #include<stdlib.h> #define THREAD_NUM 30 void * thread_inc(void *arg); void * thread_dec(void *arg); long long num = 0; pthread_mutex_t mutex; int main(int argc, char *argv[]) { pthread_t thread_id[THREAD_NUM]; int i; pthread_mutex_init(&mutex,NULL); printf("sizeof(long long) = %lu\n", sizeof(long long)); for(i=0; i<THREAD_NUM; i++){ if(i%2){ pthread_create(&(thread_id[i]), NULL, thread_inc, NULL); }else{ pthread_create(&(thread_id[i]), NULL, thread_dec, NULL); } //pthread_join(thread_id[i], NULL); //The result is OK. } for(i=0; i<THREAD_NUM; i++){ pthread_join(thread_id[i], NULL); } pthread_mutex_destroy(&mutex); printf("Result = %lld\n", num); return 0; } void *thread_inc(void *arg) { int i; pthread_mutex_lock(&mutex); for(i=0; i<50000000; i++){ num += 1; } pthread_mutex_unlock(&mutex); return NULL; } //两个函数临界区划分范围不同,thread_inc划分范围大,但是其它线程等待时间长;thread_dec划分范围小,但是lock、unlock函数调用那个次数多----需要折中 void *thread_dec(void *arg) { int i; for(i=0; i<50000000; i++){ pthread_mutex_lock(&mutex); num -= 1; pthread_mutex_unlock(&mutex); } return NULL; }$ gcc pthread_mutex_test.c -D_REENTRANT -lpthread $ ./a.out sizeof(long long) = 8 Result = 0 -------------------------------------------------------------------------------------------------------
/************************************************************************* > File Name: chat_pthread_client.c > Author: xjhznick > Mail: xjhznick@gmail.com > Created Time: 2015年04月03日 星期五 16时30分34秒 > Description: ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<pthread.h> #define BUFF_SIZE 100 #define NAME_SIZE 20 void error_handling(char *message); void *send_msg(void *msg); void *recv_msg(void *msg); //Global data section char name[NAME_SIZE] = "[DEFAULT]"; char msg[BUFF_SIZE]; int main(int argc, char *argv[]) { int sock_server; struct sockaddr_in addr_server; pthread_t pthread_id_send, pthread_id_recv; void *thread_ret; if(argc!=4){ //命令行中启动服务程序仅限一个参数:端口号 printf("Usage : %s <IP> <port> <name>\n", argv[0]); exit(1); } sprintf(name, "[%s]", argv[3]); //调用socket函数创建套接字 sock_server = socket(PF_INET, SOCK_STREAM, 0); if(-1 == sock_server){ error_handling("socket() error."); } memset(&addr_server, 0, sizeof(addr_server)); addr_server.sin_family = AF_INET; addr_server.sin_addr.s_addr = inet_addr(argv[1]); addr_server.sin_port = htons(atoi(argv[2])); //绑定 if(-1 == connect(sock_server, (struct sockaddr*)&addr_server, sizeof(addr_server))){ error_handling("Error connect()"); } pthread_create(&pthread_id_send, NULL, send_msg, (void*)&sock_server); pthread_create(&pthread_id_recv, NULL, recv_msg, (void*)&sock_server); pthread_join(pthread_id_send, &thread_ret); pthread_join(pthread_id_recv, &thread_ret); fputs("End of Client!\n", stderr); //断开连接,关闭套接字 close(sock_server); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } void *send_msg(void *arg) { int sock = *((int *)arg); char name_msg[NAME_SIZE+BUFF_SIZE]; while(1){ //puts("Input Message(Q quit):"); fgets(msg, BUFF_SIZE, stdin); if( !strcmp(msg, "q\n") || !strcmp(msg, "Q\n") ){ fputs("Quit!\n", stderr); close(sock); exit(0); } sprintf(name_msg, "%s %s", name, msg); write(sock, name_msg, strlen(name_msg)); // fputs("Sent a message!\n", stderr); } return NULL; } void *recv_msg(void *arg) { int sock = *((int *)arg); char name_msg[NAME_SIZE+BUFF_SIZE]; int str_len; while(1){ str_len = read(sock, name_msg, NAME_SIZE+BUFF_SIZE-1); if(str_len < 0) return (void*)-1; name_msg[str_len] = 0; fputs(name_msg, stdout); } return NULL; }/************************************************************************* > File Name: chat_pthread_server.c > Author: xjhznick > Mail: xjhznick@gmail.com > Created Time: 2015年04月03日 星期五 15时58分53秒 > Description:基于多线程的聊天程序--服务器端 ************************************************************************/ #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h> #include<sys/socket.h> #include<pthread.h> #define BUFF_SIZE 100 #define CLIENT_MAX 256 void error_handling(char *message); void *client_handler(void *arg); void send_msg(char *msg, int len); int count_client = 0; int socks_client[CLIENT_MAX]; pthread_mutex_t mutex; int main(int argc, char *argv[]) { int sock_server; int sock_client; struct sockaddr_in addr_server; struct sockaddr_in addr_client; socklen_t size_addr_client; pthread_t pthread_id; if(argc!=2){ //命令行中启动服务程序仅限一个参数:端口号 printf("Usage : %s <port>\n", argv[0]); exit(1); } pthread_mutex_init(&mutex, NULL); //调用socket函数创建套接字 sock_server = socket(PF_INET, SOCK_STREAM, 0); if(-1 == sock_server){ error_handling("socket() error."); } memset(&addr_server, 0, sizeof(addr_server)); addr_server.sin_family = AF_INET; addr_server.sin_addr.s_addr = htonl(INADDR_ANY); addr_server.sin_port = htons(atoi(argv[1])); //调用bind函数分配IP地址和端口号 if( -1 == bind( sock_server, (struct sockaddr*)&addr_server, sizeof(addr_server)) ){ error_handling("bind() error"); } //监听端口的连接请求,连接请求等待队列size为5 if( -1 == listen(sock_server, 5) ){ error_handling("listen() error"); } // while(1){ size_addr_client = sizeof(addr_client); sock_client = accept( sock_server, (struct sockaddr*)&addr_client, &size_addr_client); pthread_mutex_lock(&mutex); socks_client[count_client++] = sock_client;//Lock 访问公共代码区 pthread_mutex_unlock(&mutex); pthread_create(&pthread_id, NULL, client_handler, (void *)&sock_client); pthread_detach(pthread_id);//销毁线程 printf("Client IP:%s \n", inet_ntoa(addr_client.sin_addr)); }//end of while //断开连接,关闭套接字 close(sock_server); pthread_mutex_destroy(&mutex); return 0; } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } void *client_handler(void *arg) { int sock_client = *((int *)arg); int str_len = 0, i; char msg[BUFF_SIZE]; while((str_len = read(sock_client, msg, BUFF_SIZE-1)) > 0){ //msg[str_len] = 0; //printf("Received a messgae: %s", msg); send_msg(msg, str_len); } pthread_mutex_lock(&mutex); for(i=0; i<count_client; i++){//remove disconnencted client if(sock_client == socks_client[i]){ while(i++ <= count_client-1){ socks_client[i] = socks_client[i+1]; } break; } } count_client--; pthread_mutex_unlock(&mutex); close(sock_client); return NULL; } void send_msg(char *msg, int len)//send message to all clients { int i; pthread_mutex_lock(&mutex); for(i=0; i<count_client; i++){ write(socks_client[i], msg, len); } pthread_mutex_unlock(&mutex); }
秋风对本书的所有笔记 · · · · · ·
-
第265页 第17章 优于select的epoll
每次调用select函数时向操作系统传递监视对象信息(select监视socket变化,socket由os管理),...
-
第273页 第17章 优于select的epoll--LT ET
例如针对输入缓冲: 条件触发(Level Trigger)--只要输入缓冲中有数据就会一直通知该事件; 边...
-
第184页 第18章 多线程服务器端的实现
-
第399页 第24章 实现简单的Web服务器端
Web服务器是以HTTP协议为基础传输超文本的服务器。 HTTP--Stateless协议 Web协议采用HTTP协议...
说明 · · · · · ·
表示其中内容是对原文的摘抄