socket 공유시의 경쟁에 관한 질문...
제목에서 처럼 소켓을 여러 프로세스 또는 스레드 간에 공유하는 부분에 대해 궁금증이 있어 글을 몇자 남깁니다.
부연 설명을 해 주시면 감사하겠습니다.
일단 상황을 말씀드리자면...
1. listen 소켓을 global 변수로 둔다.
2. 여러 스레드에서 이 listen 소켓을 이용해 accept 대기를 한다.
※ listen 소켓은 SO_REUSEADDR 옵션을 주었습니다.
위와 같은 상황에서 처음에는 뮤텍스를 하나 두고서
- 이 뮤텍스를 얻기 위한 경쟁에서 승리(?!)하는 스레드가 뮤텍스 locking 후
- accept 대기를 하고...
- accept가 수행 된 후엔 뮤텍스를 unlock
하는 구조로 작성하였습니다.
pthread_mutex_lock(&lock_4_listen); sock_conn = _accept(listen_sock, (struct sockaddr*) &sa, &sa_len); pthread_mutex_unlock(&lock_4_listen);
근데 플랫폼이 linux이다보니 pthread_mutex_unlock에서 자꾸 segmentation fault 나는 관계로,
어찌어찌하다 우연히 뮤텍스 lock/unlock 코드를 주석으로 막고 돌렸는데도 잘 돌아가네요.
이 부분에서 제가 궁금한 것이...
지금처럼 뮤텍스 lock/unlock 없이 모든 스레드가 동시에 하나의 listen 소켓에 대기를 하여도 SO_REUSEADDR 옵션만 주어진다면 충돌 없이 운영체제 차원에서 accept를 수행할 순서를 정해주는 것인가요?
만일 그렇다면 뮤텍스를 쓸 필요가 전혀 없다는 생각이...
눈에 보이는 결과는 그런 것 같지만, 이 부분에 대해서 좀 더 명확한 설명을 듣고자 합니다.
많은 조언 부탁드립니다.
비가 오네요... 좋은 소식을 가져다 주는 봄비였으면 합니다.
확실히 unlock에서 죽는지 확인하시고요. gdb로 체크lock_
확실히 unlock에서 죽는지 확인하시고요. gdb로 체크
lock_4_listen의 값에 영향을 미칠만한 부분을 찾아보세요.
전역변수라면... 전후의 선언된 다른 전역변수가 힙크기에 맞게 사용되고 있는지
printf문에 인자를 잘못 사용했다던지.....
표준함수가 오류를 낼경우는 대부분이 사용자 프로그래밍 잘못입니다.
오류가 난 원인을 알아내지 못한채 피해가면 후일 반드시 보복이 날아 옵니다. ^^;
리눅스가 그렇게 만만한 OS를 아닙니다. 리눅스를 믿으세요 ^^;
그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.
제 생각에도, alsong 님의 의견과 같이 전역변수 lock_4_lis
제 생각에도, alsong 님의 의견과 같이 전역변수 lock_4_listen 의 근처에 있는 array 나 포인터 변수등이 값을 넘어가면서 mutex 변수가 뭉개져 버리는게 아닐까 하는 추측이네요.
처음에는 프로그램이 잘 돌다가 어떤 순간에 SIGSEGV 가 발생된다면 그럴 확률이 높겠지요.
pthread_t 를 신뢰하고 아주 애용하고 있는 사람으로, 그런 문제가 linux 에서 발생된다면, 이미 전 어마어마한 재앙 수준의 일이 벌어졌을겁니다.
그럼.
[quote]확실히 unlock에서 죽는지 확인하시고요[/quote]
확실히 unlock에서 죽는답니다... 뱉어낸 core dump에서 그리 말해주고 있으니 ㅜㅡ
lock_4_listen은 제가 위에서 적은 부분 말고는 사용되는 곳이 없답니다.
destroy 하는 곳 말고는...
제 개인적인 생각입니다만,
unistd.h 헤더를 보면... _POSIX_THREAD_PROCESS_SHARED 가 정의된 부분이 주석으로 막혀있고... (2.6버전에는 NPTL이 들어가면서 이 기능이 된다고는 합니다만...)
리눅스에선 스레드 = 프로세스로 알고있는지라 혹여 global로 된 lock_4_listen 이 공유되다가 문제를 일으키는 것이 아닐까 하는 막연한 (이런게 안좋다는 건 알지만, 원인을 몇일째 찾지 못한 마당에 이러한 추측이라도 -_-;;; ) 생각도 해 봅니다.
특히나 이렇게 segmentation fault가 매번 생기는 것이 아니라 잘 돌아가다 갑자기 생기는 관계로 님들 말씀처럼 다른 곳에 문제가 있을지도 몰겠다... 는 생각을 하는 상황에선 별 생각을 다 해봅니다.
참 그리고... 지금처럼 뮤텍스 lock/unlock 없이 모든 스레드가 동시에 하나의 listen 소켓에 대기를 하여도 SO_REUSEADDR 옵션만 주어진다면 충돌 없이 운영체제 차원에서 accept를 수행할 순서를 정해주는 것인가요?
라는 질문에 대한 조언도 궁금합니다.
만약 OS 차원에서 이 스케쥴링이 된다면 굳이 mutex를 쓰지 않아도 되겠기에.
테스트는 계속 돌려봐도 아직은 별 문제는 없습니다만, 답변을 기다리며 더 테스트를 해 보겠습니다.
오늘 날씨가 쌀쌀하네요... 좋은 하루 되세요
accept 하고 SO_REUSEADDR 옵션하고 상관없는 걸로 알고 있
accept 하고 SO_REUSEADDR 옵션하고 상관없는 걸로 알고 있습니다.
그 옵션은 새로운 리슨 소켓을 해당 포트에 바인딩할 때 의미 있는 것 아닌가요?
아 또하나 있는데, accept 주변을 동기화 객체로 막는 것이 속도 때
아 또하나 있는데, accept 주변을 동기화 객체로 막는 것이 속도 때문만이 아니라 같은 fd를 accept하지 못하는 OS 때문이기도 하다고 stevens 아저씨 책에는 나와 있군요...
혹시나 -D_REENTRANT(없으면) 한번 추가 해보세요.acc
혹시나 -D_REENTRANT(없으면) 한번 추가 해보세요.
accept가 thread safe한 unix가 있다고는 들었습니다만
리눅스가 thread safe한지는 잘 모르겠습니다.
별도움이 안되었군요... ㅡㅡ;
그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.
core dump로 뱉어낸 것을 잠깐 올려봅니다.
테스트 중인 플랫폼은 리눅스입니다.
Linux my_server 2.4.18-14smp #1 SMP Wed Sep 4 12:34:47 EDT 2002 i686 i686 i386 GNU/Linux
-D_REENTRANT 심볼을 정의하고 컴파일 했을때 나온 에러이니...
앞서 올라온 다른 글들을 보면... pthread_mutex_unlock에서 SIGSEGV 난다는 분들이 몇분 되시던데... 답글들을 보며 정리를 해봐도 이거다... 라는 명확한 답이 안보입니다.
리눅스에서 스레드는 프로세스니까... pthread의 뮤텍스 보단 세마포어를 써야하는건가 싶기도 하고...
일단 pthread_mutex_unlock이 리눅스에서 SIGSEGV 발생시키는 이유를 아시는 분 계신가요?
적고보니 횡설수설이군요. (--)(__)(--);;
세마포어로 방향전환 했습니다.
제목처럼 세마포어로 방향전환 했습니다.
많은 조언 주신 분들 감사드려요.
세마포어로 돌리니 문제없이 잘 돌아가네요.
리눅스에서 뮤텍스는... 이라는 의문점을 가지고 가네요... 계속 찾아봐야죠^^
댓글 달기