[완료]multi thread 사용시 thread create시 마다 VSZ 증가 이유가 궁금합니다.
글쓴이: whxoans / 작성시간: 목, 2008/12/04 - 11:45오전
얼마전에도 관련된 질문을 올렸었는데 거두절미하고 말씀드리면
multi thread 기반 web서버를 만들어보고 있습니다.
2가지 문제에 봉착했는데
첫째, main thread에서 SISPIPE를 무시하도록 했습니다.
Quote:
하지만 SIGPIPE를 받으면 종료가 되고 있습니다.signal(SIGPIPE, SIG_IGN);
둘째, thread pool이 아닌 accept()로 연결이 발생되면 HTTP를 처리하는 thread를 생성하는데 생성시 마다 VSZ가 급격히 증가합니다. 해당 문제로 pthread_join으로 처리까지 기다려보기도 해보고 pthread_detach해 자식 thread에서 pthread_exit를 해보기도 했지만 처리가 끝나도 자원을 반환하지 않고 있습니다. 그래서 동적할당을 안쓰고 배열를 쓰는 방법 등으로 메모리 릭의 여지를 두지 않게 했습니다.
첫째 사항은 gdb를 이용해 debug모드로 돌려서 확인을 했습니다. gdb에서
Quote:
로 시그널을 무시하게 했더니 잘 넘어가고 있는데 그냥 돌리면 문제가 발생합니다.handle SIGPIPE noprint nostop pass
둘째 사항은 서버를 띄우고 지속적으로 요청하면서 ps로
Quote:
위와 같이 감시를 했습니다.
while [ 1 ];do ps aux | grep HTTP | grep -v grep;echo "";sleep 1;done
컴파일은
Quote:
처럼 했고 main의 첫번째 인자는 listen할 port입니다.아래 코드를 올리니 지적을 부탁드리겠습니다.gcc -g -o HTTPServer -D_REENTRANT -lpthread HTTPServer.c
/* * HTTPServer.c * * Created on: 2008. 11. 27 * Author: 조태문 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <pthread.h> #define BUFSIZE 1024 #define LINESIZE 100 #define _REENTRANT // 확인차 void * clnt_connection(void *arg); // HTTP처리 thread char* strtrim(char *str); // string trimer void send_data(FILE* fp, char* ct, char* file_name); // response 전송 char* content_type(char * file); // content_type 협상 void send_error(FILE* fp); // error 전송 void error_handling(char *message); // error 메세지 출력 후 종료 //pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int main(int argc, char **argv) { int serv_sock; int clnt_sock; int stat; struct sockaddr_in serv_addr; struct sockaddr_in clnt_addr; int clnt_addr_size; char buf[BUFSIZE]; pthread_t thread; signal(SIGPIPE, SIG_IGN); // client에서 connection if(argc!=2){ printf("Usage : %s <port>\n", argv[0]); exit(1); } signal(SIGPIPE, SIG_IGN); // create sock serv_sock=socket(PF_INET, SOCK_STREAM, 0); if(serv_sock==-1) error_handling("socket() error"); // bind memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(atoi(argv[1])); if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) error_handling("bind() error"); // listen if(listen(serv_sock, 5)==-1) error_handling("listen() error"); while (1) { clnt_addr_size=sizeof(clnt_addr); //accept //pthread_mutex_lock(&mutex); clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); printf("연결요청 : %s:%d\n", inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port)); if ( pthread_create(&thread, NULL, clnt_connection, &clnt_sock) != 0 ){ perror("쓰레드 생성 실패 : "); } //else pthread_detach(thread); pthread_join(thread,(void **)stat); //pthread_mutex_unlock(&mutex); } return 0; } /* 쓰레드 영역 */ void * clnt_connection(void *arg) { int clnt_sock=*((int*)arg); char req_line[LINESIZE]; FILE* clnt_read; FILE* clnt_write; char method[10]; char ct[15]; char file_name[30]; printf("thread ID[%d]\n", pthread_self()); clnt_read = fdopen(clnt_sock, "r"); clnt_write = fdopen(dup(clnt_sock), "w"); fgets(req_line, LINESIZE, clnt_read); fputs(req_line, stdout); if(strstr(req_line, "HTTP/")==NULL){ send_error(clnt_write); fclose(clnt_read); fclose(clnt_write); return; } strcpy(method, strtok_r(req_line, " /")); strcpy(file_name, strtok_r(NULL, " /")); strcpy(ct, content_type(file_name)); if(strcmp(method, "GET")!=0){ send_error(clnt_write); fclose(clnt_read); fclose(clnt_write); return; } while(1){ fgets(req_line, LINESIZE, clnt_read); fputs(req_line, stdout); if(strcmp(strtrim(req_line),"")==0) break; } fclose(clnt_read); send_data(clnt_write, ct, file_name); close(clnt_sock); //pthread_exit(0); } /* 쓰레드 영역 */ char* strtrim(char *str) { int end=strlen(str); while(str[end]<=' ' && end>0) end--; str[end+1]=0; while(*str<=' ' && *str!=0) str++; return str; } void send_data(FILE* fp, char* ct, char* file_name) { char protocol[]="HTTP/1.0 200 OK\r\n"; char server[]="Server:Best Http Server \r\n"; char cnt_len[]="Content-length:2048\r\n"; char cnt_type[LINESIZE]; char buf[BUFSIZE]; FILE* send_file; int len; sprintf(cnt_type, "Content-type:%s\r\n\r\n", ct); send_file = fopen(file_name, "r"); if(send_file == NULL){ send_error(fp); return; } /* 헤더 정보 전송 */ fputs(protocol, fp); fputs(server, fp); fputs(cnt_len, fp); fputs(cnt_type, fp); /* 요청 데이터 전송 */ while( len=fgets(buf, BUFSIZE, send_file ) != 0) { fputs(buf, fp); fflush(fp); } fflush(fp); fclose(fp); } char* content_type(char* file){ char extension[LINESIZE]; char file_name[LINESIZE]; strcpy(file_name, file); strtok(file_name, "."); strcpy(extension, strtok(NULL, ".")); if(!strcmp(extension, "html")||!strcmp(extension, "htm")) return "text/html"; if(!strcmp(extension, "txt")||!strcmp(extension, "c")) return "text/plain"; return "text/plain"; } void send_error(FILE* fp) { char protocol[]="HTTP/1.0 400 Bad Request\r\n"; char server[]="Server:Best Http Server \r\n"; char cnt_len[]="Content-length:2048\r\n"; char cnt_type[]="Content-type:text/html\r\n\r\n"; char content[]="[geshifilter-html]<head><title>NETWORK</title></head>" "<body><font size=+5><br>오류 발생! 요청 파일명 및 요청 방식 확인!" "</font></body>[/geshifilter-html]"; fputs(protocol, fp); fputs(server, fp); fputs(cnt_len, fp); fputs(cnt_type, fp); fflush(fp); } void error_handling(char *message) { fputs(message, stderr); fputc('\n', stderr); exit(1); }
Forums:
자문자답;
SIGPIPE 발생시 종료되는 것은 테스트 과정에 컴파일 해야할 소스를 혼동한 것으로 생각됩니다.
signal(SIGPIPE, SIG_IGN);
VLZ 증가 원인은 단순 memory과 thread가 정상적으로 소멸되지 않아 발생한 것이네요;
memory leak은 valgrind를 돌려서 확인 후 하나하나 따라가서 잡았습니다.
thread가 정상적으로 소멸되지 않은 부분은 예외 처리 과정에
pthread_exit를 포함 시켰습니다.
아 챙피챙피.
댓글 달기