데드락 문제는 어떻게 해결 할 수 있나요?

jagalchee의 이미지

Posix Thread 로 멀티 쓰레드 프로그래밍을 하고 있는데요.

만약 어떤 쓰레드가 mutex 락을 걸고 나서, unlock 을 하지 못하고 갑자기 죽어버리거나 하면 이 상태를 데드락이라고 부른다고 알고 있습니다.

데드락 상태가 되면 나머지 쓰레드들은 mutex 가 unlock 될때까지 계속 기다린다고 알고 있는데요.. 대게의 경우 이런 데드락 상태일 경우엔 프로그램 상에서 어떻게 처리를 해주면 되나요?
어떻게 처리를 해주어야 할지 잘 감이 안오네요. 답변 부탁드립니다.

yielding의 이미지

데드락 하면 떠오르는 시가 있습니다.

윤석중님의 '먼길'

Quote:

먼 길

아기가 잠드는 걸
보고 가려고
아빠는 머리맡에
앉아 계시고,

아빠가 가시는 걸
보고 자려고
아기는 말똥말똥
잠을 안자고

이미 데드락이 만들어진 상태에서 데드락을 풀려면 데드락을 발생시킨
프로세스/쓰레드 그래프에서 한 넘을 죽여서 데드락을 발생시킨 자원을
풀어줘야겠죠.

애초에 프로그램이 데드락이 발생하지 않도록 신경써서 코딩해야합니다.
즉, 아빠가 가시거나, 아기가 자거나 :D

Life rushes on, we are distracted

SoulreaveR의 이미지

-_-)=b

kuma의 이미지

몇년간은 Lock 을 사용하지 않았습니다. 가능하면 Queue 로 동기화 I/O 를 수행하여 Shared Memory 나 기타 Resource 의 동시접근을 막았습니다.

그러나...., 상황이 그렇게만 항시 전개 되지 않아서 어쩔수 없이 Lock 을 써야만 하는 상황이 발생하였습니다.

Lock 과 Unlock 부분이 너무 많아 어쩔줄 몰라하다 2가지 방법을 사용하고 있습니다.

사용환경은 Windows-NT 계열에 Visual C/C++ 6.0 입니다.

1. Lock 후 Lock 했음을 Trace 로 남기고 Unlock 후 다시 Trace 로 남겨 걸고 있는 Processor 를 추적가능하게 만들었습니다.

2. Visual C 의 SEH 를 사용했습니다. ( __try __finally ) 아마 이부분은 C++ 의 try catch 로 바꿀수 있지 않을까 생각됩니다. SECH 로 Function 내 Unlock 에 대한 위험 부담을 줄였습니다.

bugiii의 이미지

C로 만들셔야 한다면 pthrad 의 cleanup 도 한가지 방법일 것이고, __try / __finally 를 사용할 수 있는 환경이라면 이것도 리소스 해제에 아주 유용한 방법입니다.

만약, C++ 를 사용할 수 있다면 생성자와 소멸자를 이용한 리소스 획득/해제가 가장 안전하고 손이 덜 가는 방법이라고 생각합니다. 현재 사용하고 계시는 환경에 C++를 사용할 수 있다면 ScopeGuard 를 도입해보시라고 강력하게 권해드리고 싶습니다. 정말 편합니다!!!

http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/

mach의 이미지

앞에서 이미 좋은 답변들이 나왔습니다.
-애초에 피하자....by yielding
-Queue... by kuma
-리소스...ScopeGuard ... by bugiii
좋은 해결입니다.

이해를 돕기 위해 원론적으로 사족을 조금 달자면 아래와 같습니다.

다음의 4가지 조건을 모두 만족해야만 deadlock이 발생합니다.

1) mutual exclusion
- 자원이 공유(동시진입)되지 않음
- 동시에 단 한개의 쓰레드(프로세스)만이 자원에 접근 가능함
2) hold and wait
- 한 쓰레드(프로세스)에서 동시에 두개의 자원을 가져야만, 처리가능한 연산
- 두개의 자원을 동시에 필요로 하는 연산처리
3) no preemption
- 일단 한개의 자원을 어떤 쓰레드(프로세스)가 강점하면, 그 누구도 뺏을 방법이 없음
4) circular wait
- 자원에 대해 대기 그래프를 그려보면, 이 그래프에는 cycle이 존재

데드락이 발생하지 않게 하려면?
1~4 중 하나라도 가능하지 않게 하면됨

1) mutual exclusion
- 자원을 공유하게 만든다(완전! 재진입되게 만든다) 
- 실전에서는 아주 어려운 작업임(운영체제 만드는 수준의...)

2) hold and wait
- 동시에 한개 이상의 자원을 요구하지 못하게 한다.
- 데드락이 될지 모르는 모든 요청에 대해 reject한다.
- 모든 자원에 대한 모든 접근은 동시에 이뤄지게 한다.
- 현재 소유한 자원을 free한 이후에 동시에 다수개 자원을 요청하도록 한다.

3) no preemption
- 자원을 preemtable하게 한다
- 실전에서는 아주 어려운 작업임
- 역시 운영체제 제작하는 수준의 코드가 필요...

4) circular wait
- 자원에 대해 순차적으로 요청하게 만든다.

질문하신 경우는 "락을 걸고 조용히 사망한 경우,
즉, lock건 쓰레드가 unlock하게 내정된 구조인데, 영원히 unlock하지 않는"에 해당하므로
다음과 같이 해석됩니다.
1) mutual exclusion
- lock은 해제하기 전에 풀리지 않는다.
이때 아무도 재진입이 불가하다.
2) hold and wait
- lock을 걸고 무한히 기다리고 있는 형국이다.
3) no preemption
- 그 어떤 코드도 락을 풀려고 하지 않고 있다.
4) circular wait
- 락이 풀리기를 모두 대기하고 있다.
4가지 조건이 만족되니, deadlock이 되고, 다른 프로세스는 starvation(livelock)상태에 빠지게 되겠습니다.
deadlock -> starvation인 경우입니다.(반대의 경우, s->d 는 없음)
이미 deadlock이 발생한 경우에는 방법이 없습니다. 죽이고 리소스를 회수해야지요. 강제로 말입니다.
이미 죽었으니, 리소스를 강제로 회수해야 합니다.! 그러한 방법이 코딩되어 있지 않다면, 전부 죽여야겠네요.

발생하기 전에 미연에 방지하는 것이 역시나, 가장 좋은 해결책이라고 생각됩니다.

데드락이 발생할 가능성은 다양하지만, "락걸고 죽는...."이라는
소위 락메카니즘에 의해 데드락이 발생한 경우가 아닌, 리소스 비반납이라는
이상한(?) 경우에 해당한다면, bugiii님이 제시하신 언어수준의 scope guard를 사용하는것이 좋겠습니다.
음, 간단히 만드셔도 좋을듯하고, 아니면, smart pointer등을 공부하셔서 직접만드시는것도 방법이겠습니다.
C++의 경우 ZThread라는 프레임웍에서도 (http://zthread.sourceforge.net/) 좋은 메카니즘을 제공합니다.

그러나, 역시 항상 유의하면서 코딩하는게 좋겠지요?

- 필연적으로 락을 걸어야 하는 경우에는, critical section(lock~unlock사이의 코드)에서
는 위험한 코드를 기술하지 않는다.

Critical Section 내에서 피해야 좋은 코드들
- 쓰레드 또는 프로세스가 사망할 가능성이 있는 코드는 피한다.
- 위험한 길은 조심하다가 빠르게 지나가듯이, 빠르게 수행하도록 코드를 잘~ 보정한다.
- 무한히 다른 것(조건, 입력등등)을 기다리는 코드는 피한다.
- 락을 걸때는 아주 간단한 코드에 대해서 걸도록 유의한다.(함수등을 필할 수 있으면 아주 좋다)
- 락내에서 사용된 코드는 아주 간결하게 작성한다.
- 혹시, 쓰레드 또는 프로세스가 정상 또는 비정상 사망할 경우 소유한 자산(자원)은 반드시 반납하게 작성한다.
(C++의 smart pointer등 scope에 의한 guard 메카니즘처럼 프로그램 언어수준에서 자원반납에 대한 확실한 메카니즘을 제공하는 좋은 것들을 사용하는것이 이 경우에는 좋습니다.)

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

dudungsil의 이미지

class CCriticalSection
{
public:
	class Owner
	{
	public:
		explicit Owner (CCriticalSection& crit);
		~Owner ();
	private:
		CCriticalSection& m_crit;
	};

	CCriticalSection () { Initialize... }
	~CCriticalSection () { Delete... }

	void Enter () { EnterCriticalSection (&m_cs); }
	void Leave () { LeaveCriticalSection (&m_cs); }
private:
	CRITICAL_SECTION	m_cs;
};

CCriticalSection::Owner::Owner (CCriticalSecition& crit)
: m_crit (crit)
{
	m_crit.Enter ();
}

CCriticalSection::Owner::~Owner ()
{
	m_crit.Leave ();
}

실제로 사용하는 부분에서는 상황에 따라서 직접 Enter ()와 Leave ()를 호출하던가

CCriticalSection cs;

void SomeFunc ()
{
    CCriticalSection::Owner lock (cs);
    // TODO: 락이 필요한 일
}

뭐 간단히 쓰기에는...

산넘어 산

yielding의 이미지

andrei alexsandrescu의 라이브러리가 소개되서

몇 개를 더 소개드리면

mojo (protocol):
move consturctor 불필요한 temporary를 가능한 안만들 수 있도록 만든 lib. (expression template와 더불어 수치계산, 특히 matrix 관련 코드를 만들때 사용 가능)

flex_string :
modern c++ desing 1장에서 그토록 강조하는 policy-based design의 결정판(smart pointer와 더불어) . boost의 phoneix 라이브러리에 flex_stirng의 버그 패치판이 있습니다.

ScopeGuard:
위에서 소개되었죠.

discriminated_union :
variant impl. boost에도 variant가 있죠. 실제도 사용 가능하겠지만 공부가 많이 됩니다.

이외에
hierarchytrait, inline_container, enforcement, asserter (smart_asserter)등의 작고 깔끔하지만 엄청 공부되는 라이브러리가 있습니다.

http://www.cuj.com/experts/ 의 expert 포럼에 Generic<Programming> section에 연재되었고 이 친구의 홈페이지의 publication(www.moderncppdesign.com) 에 가면 전부 링크가 되어 있습니다

마지막으로 modern c++ design, "아직도 C++에 대해 더 쓸글이 있나는 의문을 단번에 깨드려 버린 멋진 책" 이라는 소갯글이 이 책의 가치를 잘 설명하는거 같습니다.

흠, 그리고 제가 앞에서 소개드린 윤석중 님의 동시 '먼 길'은 뜻밖에 일제에 의해 징용을 가게 되는 사람 집안의 이야기라고 하네요.. 슬프군요. 이 데드락은
안풀렸더라면 좋았겠습니다. :cry:

Life rushes on, we are distracted

bugiii의 이미지

오옷... yielding 님의 글 많은 도움이 되었습니다. 감사합니다.

kyuseo의 이미지

시스템적으로 데드락 가능성을 판단할 수있는

데드락 디텍터를 만들어서 자동화 하여 관리를 하시기를 권해드립니다.

저도 며칠전에 엄청 고생했는데 ^^; ( 고생흔적 : http://a.tk.co.kr/431 )

데드락 디텍터를 만들고도 안쓴것이 화근이었네요...

93년부터 프로그래밍을 독학한 게임 프로그래머 kyuseo 입니다.
블로그는 http://a.tk.co.kr

93년부터 프로그래밍을 독학한 게임 프로그래머 kyuseo 입니다.
블로그는 http://a.tk.co.kr

dong1036의 이미지

데드락 방지할려면 상당한 자원을 소비하는 걸로 알고 있는데..

데드락 현상이 자주 일어나지 않는다면...

걍... 무시해버리고.. 프로세스를 다시 실행하는 것이 나을수도 ..

음 냐냐~

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.