system함수가 thread-safe한가요??
글쓴이: hatbary / 작성시간: 수, 2004/01/07 - 11:21오후
안녕하세요..
스레드 풀을 만들어 놓고, 각각의 클라이언트들에게 서비스를 제공하는 서버를 만들고 있는데요.
서버는 클라이언트로부터 파일도 전송을 받는데, 이게 압축된 파일이라서 압축된 파일중 특정파일만 골라서 다른 파일과 압축하여 다시 전송해줘야 할 필요가 있거든요..
그래서 zip알고리즘을 구현해서 쓰려구 했는데, 그냥 system함수 써서, 직접 zip명령어를 호출하려구 합니다..(원래 system쓰는거 안조아하지만 실력이 딸려서..ㅠㅠ)
근데, 제가 알기로는 system함수가 fork->exec->sh...머..이런식으로 동작한다고 알고 있는데, 만약 스레드 내에서 이 system함수를 호출한다면 문제가 될 소지가 있지 않을까 라는 생각이 들어서 질문 올립니다..
어떤 용어를 써야 할지 좀 난감해서 그냥 system함수가 thread-safe한가라구 물어본거거든요..
이에 대한 답변을 부탁드립니다..
그럼 답변에 미리 감사 드리면서...
Forums:


11
동작하고 있는 스레드가 열개라고 치고..
fork()를 하면..문제가 발생합니다.
즉, 현재 프로세스에서 10개의 스레드들은 각각 저마다의
메모리를 차지하고 있습니다.
그리고 10개의 스레드중 한 스레드가 fork()를 호출하게 되면요
10개의 스레드를 가지고 있는 부모 프로세스와 동일한 개수의
스레드가 있는 자식 프로세스가 생성됩니다.
그러면 자식 스레드가 10개 동작하는가 하면, 모두 죽은 상태의
스레드입니다. 동작하지도 않는 스레드들이 메모리만 차지하고 있습니다.
(또 락객체 같은 것 땜에 문제가 발생할 수도 있습니다.)
자식 프로세스에서 동작하는 스레드는 부모프로세스에서
fork()를 호출한 스레드뿐입니다.
그리고 이들의 메모리는 2가지 경우에만
자동소멸될수 있고.어떤 함수호출같은걸로 해제할수 없습니다.
자동소멸되는 첫번째 경우는
프로세스가 종료할때 자동소멸됩니다.
두번째 경우는 exec()계열의 함수를 호출할때입니다.
exec()하면 프로세스의 메모리이미지가 모두 사라지고, 새로운 프로그램의
이미지로 바뀌니깐요. 그러니 이땐 죽은 스레드가 차지하는 메모리가
해제됩니다.
system()은 fork()한담에, exec()하는 것이니깐 문제가 안될것 같은
생각이 듭니다.
직접 코딩은 못해보고 이론적인 것입니다만. 될것 같네요
님이 해보시고 답글좀 올려주세요 ^^
문제 없습니다.fork 하면, 현재 thread를 제외한 모든 thr
문제 없습니다.
fork 하면, 현재 thread를 제외한 모든 thread는 닫혀지게 되며,
thread unsafe한 데이터를 내부에 가지고 있지 않으니.. 그다지 문제 없어 보입니다.
signal을 masking 해두었다면 문제가 있을지도 모르겠습니다만, 아래 코드를 보니 __sigprocmask를 사용하여 masking을 잠시 푸는 군요.
glibc-2.2.2/sysdeps/posix/system.c
1 /* Copyright (C) 1991-1999, 2000 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 The GNU C Library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public License as 6 published by the Free Software Foundation; either version 2 of the 7 License, or (at your option) any later version. 8 9 The GNU C Library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public 15 License along with the GNU C Library; see the file COPYING.LIB. If not, 16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Boston, MA 02111-1307, USA. */ 18 19 #include <stddef.h> 20 #include <stdlib.h> 21 #include <unistd.h> 22 #include <sys/wait.h> 23 #include <signal.h> 24 #include <sys/types.h> 25 #include <errno.h> 26 27 28 #ifndef HAVE_GNU_LD 29 #define __environ environ 30 #endif 31 32 #define SHELL_PATH "/bin/sh" /* Path of the shell. */ 33 #define SHELL_NAME "sh" /* Name to give it. */ 34 35 /* Execute LINE as a shell command, returning its status. */ 36 int 37 __libc_system (const char *line) 38 { 39 int status, save; 40 pid_t pid; 41 struct sigaction sa, intr, quit; 42 #ifndef WAITPID_CANNOT_BLOCK_SIGCHLD 43 sigset_t block, omask; 44 #endif 45 46 if (line == NULL) 47 /* Check that we have a command processor available. It might 48 not be available after a chroot(), for example. */ 49 return __libc_system ("exit 0") == 0; 50 51 sa.sa_handler = SIG_IGN; 52 sa.sa_flags = 0; 53 __sigemptyset (&sa.sa_mask); 54 55 if (__sigaction (SIGINT, &sa, &intr) < 0) 56 return -1; 57 if (__sigaction (SIGQUIT, &sa, &quit) < 0) 58 { 59 save = errno; 60 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); 61 __set_errno (save); 62 return -1; 63 } 64 65 #ifndef WAITPID_CANNOT_BLOCK_SIGCHLD 66 67 /* SCO 3.2v4 has a bug where `waitpid' will never return if SIGCHLD is 68 blocked. This makes it impossible for `system' to be implemented in 69 compliance with POSIX.2-1992. They have acknowledged that this is a bug 70 but I have not seen nor heard of any forthcoming fix. */ 71 72 __sigemptyset (&block); 73 __sigaddset (&block, SIGCHLD); 74 save = errno; 75 if (__sigprocmask (SIG_BLOCK, &block, &omask) < 0) 76 { 77 if (errno == ENOSYS) 78 __set_errno (save); 79 else 80 { 81 save = errno; 82 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); 83 (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); 84 __set_errno (save); 85 return -1; 86 } 87 } 88 # define UNBLOCK __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) 89 #else 90 # define UNBLOCK 0 91 #endif 92 93 pid = __fork (); 94 if (pid == (pid_t) 0) 95 { 96 /* Child side. */ 97 const char *new_argv[4]; 98 new_argv[0] = SHELL_NAME; 99 new_argv[1] = "-c"; 100 new_argv[2] = line; 101 new_argv[3] = NULL; 102 103 /* Restore the signals. */ 104 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); 105 (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); 106 (void) UNBLOCK; 107 108 /* Exec the shell. */ 109 (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); 110 _exit (127); 111 } 112 else if (pid < (pid_t) 0) 113 /* The fork failed. */ 114 status = -1; 115 else 116 /* Parent side. */ 117 { 118 #ifdef NO_WAITPID 119 pid_t child; 120 do 121 { 122 child = __wait (&status); 123 if (child <= -1 && errno != EINTR) 124 { 125 status = -1; 126 break; 127 } 128 /* Note that pid cannot be <= -1 and therefore the loop continues 129 when __wait returned with EINTR. */ 130 } 131 while (child != pid); 132 #else 133 int n; 134 135 do 136 n = __waitpid (pid, &status, 0); 137 while (n == -1 && errno == EINTR); 138 139 if (n != pid) 140 status = -1; 141 #endif 142 } 143 144 save = errno; 145 if ((__sigaction (SIGINT, &intr, (struct sigaction *) NULL) | 146 __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL) | 147 UNBLOCK) != 0) 148 { 149 if (errno == ENOSYS) 150 __set_errno (save); 151 else 152 return -1; 153 } 154 155 return status; 156 } 157 weak_alias (__libc_system, system)---
http://coolengineer.com
여러분들의 의견을 듣고 간단하게 코딩했더니 별 문제 없어보이는군요..
여러분들의 의견을 듣고 간단하게 코딩했더니 별 문제 없어보이는군요..
아래는 그냥 후다닥 만든 코드와 결과 입니다.
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> void* call(void*); int main() { pthread_t tid[10]; for(int i=0; i<10; i++) { printf("[+] thread created : %d\n",i); pthread_create(&tid[i],NULL,call,(void*)i); } sleep(20); return 0; } void* call(void* arg) { pthread_detach(pthread_self()); sleep(10-(int)arg); char cmd_unzip[132] = {'\0',}; snprintf(cmd_unzip, sizeof(cmd_unzip), "unzip -qqu test.zip *.txt -d./tmp%d", (int)arg); int res = system(cmd_unzip); printf("return : %d\n",res); if(res == 127 || res == -1) { printf("[-] fail to call system\n"); return NULL; } else if( res != 0) { printf("[-] fail to unzip\n"); return NULL; } printf("[+] done\n"); return NULL; }그런데..잠깐 또 의심가는게 바로 위에 분께서 현재 스레드를 제외한 다른 스레드가 닫힌다구 하셨는데, 스레드 풀을 만들어놓구 pthread_cont_wait()명령을 써서 스레드를 깨우는 방식이면 만들어놓은 스레드가 죽는건가요? 제가 님의 설명을 잘 이해 못하겠네요..지송^^a
암튼 여러분들의 도움을 받으니 그저 고마울 따름임다..^^
아.. 오해가 있을 것 같군요.fork 하고 나면, 자식 프로세스
아.. 오해가 있을 것 같군요.
fork 하고 나면, 자식 프로세스에서는 다른 쓰레드는 모두 닫히고 하나만 남는다는 것이었습니다.
---
http://coolengineer.com
아하~~그렇군요..답변 감사드립니다..^^
아하~~그렇군요..답변 감사드립니다..^^
댓글 달기