MultiThread 프로그래밍에 대한 조언을 듣고 싶습니다
글쓴이: kuaaan / 작성시간: 월, 2006/04/17 - 12:59오후
Quote:
과연 어떻게 해야 MultiThread환경에서 안전한 코드를 만들수 있을까요?
질문이 좀 뜬금없죠?
질문 그대로입니다.
자꾸 Mutex가 쓰레드끼리 꼬여서 데드락이 걸립니다.
잡고 고치고... 하다 이젠 지쳤습니다. ㅡ.ㅡ
나름대로 신경써서... mutex lock을 거는 것도 방향성을 만들고...
mutex를 섞어쓰지 않으려고 노력하고... 하는데도...
코드가 복잡해지고 뮤텍스가 많아지다 보니 꼬이네요...
프로그램을 설계하는 구조적인 문제도 좋고,
코드상의 테크닉도 좋고
좋은 문서를 추천해주시면 더욱 좋습니다.
쓰레드를 다루는 안전한 방법 좀 없나요??
Forums:
http://docs.sun.com/app/docs/doc/816-513
http://docs.sun.com/app/docs/doc/816-5137/6mba5vpk6?a=view
이 문서 참고 하시고요.
re-enterant function도 확인 해주셔서...
다른 걸로 대체 가능한건 대체 해주시고요.
신경을 좀 써주셔야 할겁니다.
정말 속편한건...
multi-process로 가시는 것도 ㅎㅎ;
그리고 더 좋은 내용 다른 분들이 더 달아 주실겁니다.
제가 쓰레드는 거의 사용치 않는 종족이라. 잘 몰라서 ㅎㅎ;
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <beer.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
Lock 하기전에 테스트를 먼저 하세요
무조건 바로 lock을 걸지 말고 테스트후에 거세요.
아니면 테스트 하면서 걸든지.
이미 걸린 상태라면 오류을 찍고 리턴..
멀티스레딩에서
멀티스레딩에서 데드락 문제를 잡기가 무지 어렵죠..
전 그래서 락 하기 전에 어디에서 락했다고 로그 남기고..
락 풀고나서 어디서 락 풀었다고 로그를 남깁니다.. 그러면 나중에
문제가 생겼을때 어디서 데드락이 걸렸는지 찾기 쉽거든요..
그리고 저 같은 경우에는 뮤텍스 객체를 만들어서 사용했습니다..
객체 생성자에 뮤텍스 락 코드를 넣고.. 소멸자에 언락 코드를 넣는 식입니다.
이렇게 하면 스택 범위를 벗어날 경우 자동으로 락이 풀리게 되므로 중간에 논리적인 버그로 락이 안풀리는 경우는 없었습니다.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
ps 와 gdb만 잘 쓰면
ps 와 gdb만 잘 쓰면 번거롭게 로그 추적하는 일은 피할 수 있습니다.
1. ps -auxSm
2. gdb --pid=
3. bt
------식은이 처------
길이 끝나는 저기엔 아무 것도 없어요. 희망이고 나발이고 아무 것도 없어.
linux라면 posix 표준은
linux라면 posix 표준은 아니지만
아래처럼 mutex attr을 지정해주면
recursive한 경우랑 deadlock에 대해서 에러 처리를 해줍니다.
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP
lock이 너무 많을 경우 통합해서 줄여주시는 것도
좋은 방법입니다.
그 lock을 거는 부분이 전체 작업에서 차지하는 비중이 낮다면
너무 많은 lock을 쓰실 필요가 없습니다.
권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -
권위를 의심할 것,어긋남을 존경할 것,자리잡기를 거부할 것,항상 자신을 재창조할 것 - MIT 미디어랩 -
PTHREAD_MUTEX_RECURSIVE_NP, P
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP
는 GCC 의 비표준 내부 매크로입니다. 표준 pthread 로 바꿀려면
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
함수를 사용하시면 되고, kind 에는
PTHREAD_MUTEX_ERRORCHECK 로 설정하시면 됩니다.
혹은 pthread_mutex_trylock(3)함수를 사용하여 넌블럭킹으로 작동하도록 하는 방법도 있습니다.
========================================
* 부분이 전체를 대변하는 하나의 속성일때 진리이다.
영속적이지 못한 것은 전체가 될 수 없다.
========================================
* The truth will set you free.
Quote:그리고 저 같은
그런 방법이 있군요.
미처 생각하지 못했네요.
그런데... 전 mutex를 로컬변수로 만들어 사용한적은 한번도 없는것 같은데...
thread간에 공유할 수 없는 mutex를 어디다 쓰죠? ^^a
여러분들이 답변을 달아주셨네요. 감사합니다.
공부하다 보니 몰랐던것들을 몇가지 알게 되었슴다.
1. fastmutex는 mutex에 lock을 건 thread 스스로가 또 lock을 걸면 데드락이 걸린다. 이게 싫다면 error check mutex를 사용하면 된다. (<-- 사실 이건 예전에 삽질을 통해 알았던 거구...)
2. mutex를 건 thread 외에 다른 thread가 해당 mutex에 unlock을 하면 unlock이 된다!!! (--> 이건 읽고서 놀랐습니다. 진짜 이렇게 되나? 테스트를 해봐야겠네요...)
또 뭐가 있더라...? ^^a
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
그런데... 전 mutex를
아마 Data structure에 mutex를 멤버로 더해 두고 사용한다는 말씀인것 같습니다. 저도 전역변수 mutex보다는 이 방법을 선호하는 편입니다. 코드보다는 자료구조를 lock하는 게 실수가 적다고 Butenhof 씨의 책에서 본 것 같기도 하군요. :-)
----
Let's shut up and code.
----
Let's shut up and code.
일단 쓰레드가
일단 쓰레드가 꼭필요한가 다시한번 고찰..해보고..
쓰레드가 필요할때 자원들을 불필요한 락을 걸어야 할일이 생기지 않게 적절히 설계하시고..
그래도 어쩔수 없이 락이 필요할때 그락은 크게 복잡하지 않게 처리될겁니다.
여담입니다만.. 간혹..
어떤곳은 멀티어쩌고를 매우 광신한나머지 대부분프로그램들을 멀티어쩌고로 만들어놓은곳이 있는데..
결과는 프로세스들이 서로 자원을 당겨서 결국 전체시스템이 느림보가되는걸보기도 했습니다..결국 시스템에 맞은프로그램을 짠게 아니라 프로그램그자체만 생각한거지요..
----------------------------------------------------------------------------
저는 DBMS개발자이기
저는 DBMS개발자이기 때문에 이런 문제를 아마도 가장 빈번하게
접한 사람이 아닌가 생각됩니다.
설계하신 프로그램의 구조를 제가 알 수는 없지만,
mutex 간의 deadlock을 발생시키지 않으시려면,
프로그램 내부에 존재하는 Mutex를 접근하는 개체들간의
순서(ordering)을 먼저 확립하셔야 합니다.
이런 원칙을 세우시지 않으시면, 아마도 영원히 끝나지 않을
전쟁을 하시게 되는 겁니다.
물론 코딩 실수로 발생하는 것은 논외로 하구요.
DBMS에서는 latch라고 불리는 유사한 객체에 대해서
일정한 방향성을 유지하면 deadlock이 없다고 판단하고,
결과가 그렇지 않다면, 프로그래머의 실수라고 판정합니다.
도움이 되셨는지..
고도의 추상화, 극도의 구체화, 에디슨을 그리워하다.
고도의 추상화, 극도의 구체화, 에디슨을 그리워하다.
CSP를 사용해 보세요.
http://xper.org/wiki/seminar/CommunicatingSequentialProcesses?action=highlight&value=Concurrent
^^
위에여러가지 답변도 있지만 이미만들어진 좋은 패턴들 사용하시는것도 좋습니다.
추천해드릴마한것은 boost입니다.
boost에는 여러 운영체제에 맞게 쓰레도 클래스까지 원하기 때문에
사용하시기 좋을거라 생각이 듭니다.
참고로 홈페이지는 : http://www.boost.org입니다.
그럼
Microsoft MVP VC++ 2003-2005
Quote: 그리고 저 같은
이런 방법을 비얀 아저씨는 RAII(Resource Acquiring Is Initialization)이라 하였지요 ;)
Quote: 어떤곳은
네. 그렇지요... ^^;;
제가 만든건 나름대로 멀티가 필요하다고 생각되어 구현했습니다.
네트워크 프로그램인데... 패킷을 처리하는 부분이 멀티쓰레드로 되어있거든요.
TCP/IP 통신이 있어서... 멀티쓰레드로 처리하면 IO가 일어나는 시간동안을 절약할수 있겠다 싶어서... ^^;
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
Quote:mutex 간의
성진님... 감사합니다.
저도 '우선순위'의 필요성을 어렴풋이나마 느끼고 있습니다.
그런데... 그게 어렴풋이 감은 오는데... 쉽지 않네요. ^^;
아마도.. 그게 mutex를 여러개 중첩해서 사용할때
mutex간의 '우선순위'나 '방향성'을 말씀하시는 거겠지요?
모 이런 원칙... ^^;;;
그런데 성진님... DBMS를 개발하신다구요?
대단하시네요... 우리나라에서 자체적으로 개발하는 DBMS가 몇개 없는 걸로
알고 있는데... 혹시... Uni***?? ^^;;
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
Quote:아마 Data
음... 전 아직도 이해가 잘 안가는데요...
class에 사용할 data가 들어있고,
그 생성자에 mutex lock 코드가 들어있다는 건...
data를 생성할때 lock이 걸린다는 얘긴데요...
이게 효과가 있으려면... 그 class가 local 변수(?)로 생성되어야 하는데...
local 변수는 어차피 단일 thread에 의해서만 접근되잖아요??
음... 이해가 잘 안되요...
음... RAII라... 이걸 한번 찾아봐야겠군요...
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
Quote: 음... 전 아직도
뮤텍이, 생성자에서 lock하고 소멸자에서 unlock 하는 클래스( 이 클래스를 A라 합니다.) 멤버로 있는 것이 아니고, 스레드가 공유할만한 ( 대표적으로 전역변수) 곳에 있구요. 클래스 A 생성자가 그 뮤텍을 lock, 소멸자가 unlock 한다면, 클래스 A 인스턴스를 로컬로 생성하는 경우, 어떠한 상황에서도 블럭이나 함수를 벗어날 때 소멸자가 자동 작동할 것이므로 unlock 하지 않아 deadlock 이 발생하진 않겠죠.
Coral Library Project : http://coral.kldp.net
Orion Project : http://home.megapass.net/~heesc22/
Orion Project : http://orionids.org
^^;
흠.. 직접 만드시는것도 좋지만 boost를 이용하시는방법도 좋을거라 봅니다.
boost에 mutex는 이미 RAII로 구현이 되어 있습니다 ^^:
한번 boost의 소스 참조해보시는것도 좋을거라 생각이 듭니다.
그럼
Microsoft MVP VC++ 2003-2005
Quote:linux라면 posix
음... 이게... 한 thread가 동일한 mutex에 lock을 두번걸어서 생기는 deadlock(recursive case)에 대해서만 처리해주는 거겠지요? ^^
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
위 에서 local 변수를
위 에서 local 변수를 이용한다고 하신 것들은 보통 object specific lock을 의미합니다. 대략 다음 같은 형태로 많이 사용 됩니다.
왓 미인이시다
이런 글 쓰는 사람 여긴 없던데 죄송합니다 ^^
공부는 안하면서도 이 사이트가 홈페이지로 설정되어서 글도 남기네요 ㅎ ㅎ
즐플
즐공
좋은 하루 되세요~
음.. Java를 쓰세요.
음.. Java를 쓰세요. synchronized 키워드 하나면 해결됩니다. (죄송-0-ㅋ)
synchronized 보다
자바에서도 당연히 synchronized 보다 고차원(?)의 해결책이 더 좋은 설계인 경우가 종종 있습니다. 그래서 jdk 1.5 에서 concurrent util 이 포함된거구요. Semaphore, CountDownLatch, CyclicBarrier 등등..그리고 이런 기본적인 동기화 메커니즘 이외에 멀티쓰레드에 필요한 좋은 패턴들이 java.util.concurrent 에 구현되어 있으니 c/c++로 구현하더라도 그런 패턴들의 API 를 한번 살펴보는 것도 나쁘시지는 않을 듯. http://java.sun.com/j2se/1.5.0/docs/api/ 왼쪽 위 프레임에서 java.util.concurrent 로 시작하는 패키지들을 함 클릭해보세요.
mutex라 하심은.
mutex를 몇번 만들어 보아서 아는데 deadlock이 걸리는 것은 전적으로 사용자 잘못입니다.
해결법은 mutex 사용에 있어서 원칙을 세우는 것인데 이는 대학교때 배운 내용대로 하시면 됩니다.
1. 되도록 점유 후 대기하지 말것.
2. circle이 발생하지 않게 순서 조정을 할것.
이 정도만 지켜도 왠만해서는 deadlock이 발생하지 않습니다.
무슨 기가 막힌 방식이 있으면 좋겠지만 리눅스에서는 사용자가 조심하는수 밖에 없습니다. 아니면 자원 할당 정책을 사용하게 mutex를 직접 만드셔도 됩니다.
RTOS와 같이 thread간 priority가 엄격한 경우에는 synchronization protocol인 PCP, IIP(lock후 wait하지 않을시)등을 사용하면 deadlock이 방지됩니다.
덧붙여서 위에서 spacelee님이 말씀하셨듯이 mutex를 lock한 owner가 해당 mutex를 반드시 다시 lock해야 되는 경우가 간혹 발생하는데 이때에는 recursive 속성을 init시에 지정해주시면 됩니다.
Concurrent Programming
구체적 문제를 말씀하지 않으셔서 정확한 이야기는 하기 어렵게 되어 있군요.
댁의 학문적 배경을 잘 알지도 못하면서 그냥 지나가다 멈추어서 댓글 좀 쓰겠습니다. 조금이라도 도움이 되면 좋겠습니다.
UNIX에서의 세마포어나 P-쓰레드는 이미 아시겠지만 Gray의 책을 보면
대략 기초적인 도움은 되겠고, 인터넷에 프로그래밍 정보가 넘칩니다.
Concurrent Programming의 웬만한 문제는 Andrew의 책에 다 설명이 되어있습니다.
이 책 차근차근 다 읽어 보시려면 무척 많은 시간이 걸리겠습니다.
새로운 기법을 창안하시는 것 보다는 이미 연구된 것을 잘 이해하는 것이
더 도움이 될 것 같습니다. 문제 해결을 위해서 세마포어의 수가 자꾸 늘여가고 있다면 아마도 멈추어서 곰곰 다시 생각해 볼 필요가 있지 않을까요?
소개한 두 권의 책은 제법 오래 된 책인지라 구하기 어려울지도.... 어쩌면
개정판이 있을지도 모르겠습니다. 책 안보고 오지에서 조용히 산 지가 벌써 몇년이 되었는데 요즘은 이 분야의 학교나 산업체가 어떻게 돌아가고 있는지 모르겠네요.. 이만.
Interprocess Communications in UNIX (2nd Ed)
- the Nooks & Crannies
- John Shapley Gray
- Prentice Hall
- ISBN: 0-13-899592-3
Foundations of Multithreaded, Parallel, and Distributed Programming
- Gregory R. Andrews
- Addison Wesley
- ISBN: 0-201-35752-6
저는 대개 이렇게 합니다
공유해야 하는 자원이 있고 그것을 사용하기 전에 mutex를 걸어야 한다면
매번 그것을 사용하기 전에 mutex를 거는 것이아니고,
해당 자원을 사용하는 클래스를 별도로 만들고, 그 클래스의 객체를 하나만 만들어서 프로그램에서 사용하도록 합니다. (그것을 대개 싱글톤이라고 하죠. 구현 방법은 논외로 합니다.)
그리고 그 클래스 내부에서 자원을 사용하기 전에 mutex를 걸고 사용한 후에 mutex를 풀어주는 코딩을 넣습니다.
그러면 외부의 다른 클래스에서는 그 클래스의 단 하나뿐인 객체를 통해 자원을 사용해야 하기 때문에 mutex문제가 자연적으로 해결됩니다.
Foundations of
Foundations of Multithreaded, Parallel, and Distributed Programming
... 이책... 주문했슴다. 히히...
싱글톤이라... RAII하고는 다른 것인 모양이네요.
찾아봐야지... ^^;
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------
리눅스의 쓰레드...
저도 요새 멀티 쓰레드 프로그래밍 때문에 골치가 아픈 상황입니다.. 음.. 근데 제가 의문이 가는건 과연 리눅스에서의 쓰레드가 진정한 의미의 쓰레드(-_-?)라고 부를 수 있는가 하는 점입니다. 음...
또 한가지 의문이랄까... 하는 것이 있는데요 멀티 쓰레드 프로그래밍을 하실 때 디버깅은 어떻게들 하시는지... ;; 디버깅 하기 귀찮아서 저 위쯤에 계신 분처럼.. 그냥 멀티 프로세싱 한 적도 있고요... (코어 파일을 남겨도 꽤나 손이 많이 가더군요...)
다른 분들은 어떻게들 하고 계시는지..
句日新, 日新 日新 又日新.
句日新, 日新 日新 又日新.
저 같은 경우
저 같은 경우 구조적으로 잘 디자인이 되었는지 봅니다.
디자인된 시나리오 대로 코딩을하고 그렇게 움직이는가는 면밀히 살펴봐야겠지요.
syslog나 fprintf 이용해서 로깅 함수만들어 의심나는 곳을 일일이
찍어보는 형태로 합니다.
리눅스에서의 쓰레드를 의심할 경우에는 같은 코드가 다른 OS에서는
잘 동작한다는 전제가 필요한데 그렇게 확인한 건가요?
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
리눅스에서의
리눅스에서의 쓰레드의 동작에 대해 의구심을 품는다기 보다, 커널 내부에서 프로세스와 쓰레드를 동일시되어 있다고 판단이 되서요... 음. 동작하는 것 자체에 의심을 가지고 있는 것은 아니구요... ^^;;
句日新, 日新 日新 又日新.
句日新, 日新 日新 又日新.
\ 별을 보며
\ 별을 보며 소원을 빌 때 당신이 누구인지는
\ 중요하지 않습니다. 당신이 소망하는 것이
★ 무엇이든, 포기하지 않는 한 그 꿈은 이루어
집니다. <司法試驗 合格記 中>
\ 별을 보며 소원을 빌 때 당신이 누구인지는
\ 중요하지 않습니다. 당신이 소망하는 것이
★ 무엇이든, 포기하지 않는 한 그 꿈은 이루어
집니다. <司法試驗 合格記 中>
댓글 달기