스레드 사용한 프로그램이 종료시 자원회수 방법.

ctcquatre의 이미지

안녕하세요 :)

다음과 같은 상황에 여러분들은 어떻게 처리를 하시겠습니까?
저는 아직 속 시원할만한 답을 못찾고 있네요.

상황 1) 스레드에서 malloc으로 동적할당 받아 사용하는 부분이 있습니다. 스레드의 수명은 내부 loop로 인해 프로그램 종료시간까지 입니다.

상황2) 프로그램 종료시 스레드에서 할당한 부분을 해제시켜줘야 합니다.

상황3) pthread_join과 같은 스레드 종료 함수를 사용할수 없습니다.( 스레드 코드에 종료점이 될만한 코드가 아무것도 없습니다)

저는 스레드를 pthread_detch로 해두고,
메인에서 강제로 해제시켜버립니다.

물론 꽁수를 써서 스레드 루프에 제어문을 삽입해 스레드를 종료시킬수 있지만 그렇게 하면 루프를 돌때마다 값을 검사해야 함으로 비효율적이라고 생각합니다.

제 방법의 문제는 메인과 스레드가 동시에 같은 메모리 주소를 참조할수 있다는 것에 있는것 같습니다.
순식간의 차이로 메인에서 해제한 메모리를 스레드가 참조해버리면 오류를 읽으킬 소지가 다분한것 같습니다.

프로그램이 이런 구조를 가진다면 여러분들은 주로 어떤방법을 사용하십니까?

오늘 날씨가 덥네요. 시원하게 보내세요.

chadr의 이미지

ctcquatre wrote:

물론 꽁수를 써서 스레드 루프에 제어문을 삽입해 스레드를 종료시킬수 있지만 그렇게 하면 루프를 돌때마다 값을 검사해야 함으로 비효율적이라고 생각합니다.

그다지 비효율적이라고 생각되지 않습니다.

루프에서 조건 하나 검사하는데 걸리는 시간이란 길어야 시피유 클럭 기준으로 1~2클럭밖에 안될테니까요..

ctcquatre wrote:

제 방법의 문제는 메인과 스레드가 동시에 같은 메모리 주소를 참조할수 있다는 것에 있는것 같습니다.
순식간의 차이로 메인에서 해제한 메모리를 스레드가 참조해버리면 오류를 읽으킬 소지가 다분한것 같습니다.

이럴때는 동기화 객체를 사용해서 보호해야겠지요..

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

cinsk의 이미지

pthread_cleanup_push()로, cleanup 함수를 만들어 등록시키고, main thread에서 pthread_cancel()을 부르는 방식이 적당할 것 같습니다.

ctcquatre의 이미지

cinsk wrote:
pthread_cleanup_push()로, cleanup 함수를 만들어 등록시키고, main thread에서 pthread_cancel()을 부르는 방식이 적당할 것 같습니다.

pthread_cancel함수의 경우 취소지점에 도달했을때만
취소될수 있다고 알고 있습니다.

pthread_cleanup_push로 스레드 종료 함수를 작성해 등록해두는 경우 pthread_cancel(tpid)를 부르면
즉각 처리되는가요?
"책에는 스레드 취소핸들러는 스레드가 완전히 종료되어 메모리에서 사라지기 전에 호출되는 함수이다" 라고 나와있는데.

pthread_cancel함수가 종료시점이 없으므로 스레드 취소핸들러가 불리지 않지 않은가요?

아..그리고 제어문으로 검사하는건 .. 네, 윗분 말씀대로 비효율적인 건 아닌것 같습니다..
하지만 비교할때마다 pthread_mutex_lock을 호출해야 합니다
좀더 깔끔한 방법이 있을것 같아서 여쭈어 보는겁니다.

----------------------------------------
"하지만 비교할때마다 pthread_mutex_lock을 호출해야 합니다"
부분을 수정했습니다.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

albamc의 이미지

locking 때문에 좀 비효율적일것 같긴 합니다만...

memory pool을 만들고

각각의 할당해준 memory에 reference counter를 두는건 어떨까요?

^^*

cinsk의 이미지

ctcquatre wrote:

pthread_cancel함수의 경우 취소지점에 도달했을때만
취소될수 있다고 알고 있습니다. pthread_cancel함수가 종료시점이 없으므로 스레드 취소핸들러가 불리지 않지 않은가요?

맞습니다. 물론 cancellation state를 asynchronous로 하면, 바로 종료되게 할 수 있지만, 안전하게 코드를 작성하기는 매우 힘들기 때문에, 대개는 cancellation point에서만 cancel될 수 있습니다. thread에 cancel point가 없을 경우, pthread_testcancel()를 써서 가상의 cancel point를 만들 수 있습니다.

ctcquatre wrote:

pthread_cleanup_push로 스레드 종료 함수를 작성해 등록해두는 경우 pthread_cancel(tpid)를 부르면 즉각 처리되는가요?

즉각 처리된다고 봐야 합니다. 다만, pthread_cancel()을 부른다 하더라도, 실제 cancel되는 시점이, cancellation point까지 올 때까지 pending될 수 있다는 것을 기억해야 합니다.

ctcquatre wrote:

"책에는 스레드 취소핸들러는 스레드가 완전히 종료되어 메모리에서 사라지기 전에 호출되는 함수이다" 라고 나와있는데,...

맞는 문장이지만, 좀 설명이 부족한 것 같습니다. pthread_cleanup_pop(nonzero)는 사용자가 직접 호출해서, cleanup handler를 실행하는 목적으로 쓰입니다. 따라서 cancel을 받았을 때 뿐만 아니라 일반적으로 thread를 끝낼 경우에도 cleanup handler를 이용할 수 있습니다.
ctcquatre의 이미지

cinsk님,albamc님,chadr님 모두 감사드립니다. :)

cinsk님의 답변에 pthread_testcancel에 대해 좀 찾아봤더니..
님말씀대로 cancel point를 만들어주는 역할을 하더군요.
책 헛봣나봅니다...,책에도 있네요
loop내에 이걸 삽입하면 될것 같습니다.

albamc wrote:

locking 때문에 좀 비효율적일것 같긴 합니다만...

memory pool을 만들고

각각의 할당해준 memory에 reference counter를 두는건 어떨까요?


memory에 reference counter 라..
좀 이해가 가지 않는데 ;; 조금 더 자세히 설명해주실수 없으신가요?

관심 가져주신 모든분들께 감사드립니다.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

ctcquatre의 이미지

번복하게 되서 죄송합니다..날씨가 더워지니 머리가 이상해 지는군요..

제가 왜 묻게 되었냐면
스레드 내에 loop에
epoll_wiat를 사용하고 있습니다.

while(true)
{
   e_ret=epoll_wait(.....);
   
   .....
}

이럴경우 pthread_testcancel을 넣어준다더라도 epoll이 취소지점을 가지는
함수가 아니기때문에 epoll이 블럭되는동안 스레드가 블럭되어버리므로
pthread_testcancel의 역할을 할수 없을것 같습니다.

애초부터 소스코드와 함께 올렸어야 하는건데 다시 한번 죄송합니다 (__)

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

chunsj의 이미지

ctcquatre wrote:
번복하게 되서 죄송합니다..날씨가 더워지니 머리가 이상해 지는군요..

제가 왜 묻게 되었냐면
스레드 내에 loop에
epoll_wiat를 사용하고 있습니다.

while(true)
{
   e_ret=epoll_wait(.....);
   
   .....
}

이럴경우 pthread_testcancel을 넣어준다더라도 epoll이 취소지점을 가지는
함수가 아니기때문에 epoll이 블럭되는동안 스레드가 블럭되어버리므로
pthread_testcancel의 역할을 할수 없을것 같습니다.

애초부터 소스코드와 함께 올렸어야 하는건데 다시 한번 죄송합니다 (__)

epoll_wait에 timeout을 이용하면 되지 않을까요?

ctcquatre의 이미지

epoll의 식별자에 대한 이벤트가 활발하게 일어나는 경우 timeout의 리턴이 아니라
이벤트 통지로 의해 epoll이 반환되므로 timeout값을 매우 작게 잡지 않는다면
바라던 결과를 [확실하게] 얻을수 있을것 같지 않습니다.

매우 작게 잡자면 필요 없는 루프를 수행하게 되므로 이것역시도
좀 찜찜하네요.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

albamc의 이미지

unreliable guide to locking 이란 문서에 나온

reference counter 기법을 쓰면 되지 않을까 생각했었는데

(http://www.kernelnewbies.org/documents/kdoc/kernel-locking/ref-counts.html)

좀더 생각해보니 아니군요...

핫핫... 무식해서 죄송합니다... :oops:

^^*

doogle의 이미지

저도 지금 낑낑대면서 pthread 로 작업중이라.. 이 글이 눈에 띄더군요.

결국엔 쓰레드가 자체적으로 안전하게 종료하도록 하는게 가장좋은 방법입니다.
쓰레드내에서 항상 terminated 관련상태값을 루프에서 체크하는 형태..
main thread가 종료될때는 단지 각 쓰레드의 terminated 상태값을 변경해
쓰레드가 스스로 종료되도록 해야합니다.

아무래도 블락안돼도록 코드를 손보시는게 좋을 것 같네요.

뭐.. 원론적인 예기밖엔 못드리겠습니다.. 저도 아는게 별로 없는지라... ㅡㅡ;

저같은 경우엔 쓰레드와 관련된 (위의 terminated 상태정보등) 을
클래스(실제론 C로 작업하고 있으니 단순 구조체 ㅡㅡ;; )로 만들어 처리하고
있습니다.(pthread의 Wrapper Class 비스끄름한 거죠뭐.. )

tinywolf의 이미지

저도 epoll에 관심이 좀 있는데..
블럭 상태를 취소시킬 수 있는 방법이 없나요?
소켓은 외부에서 닫아버리면 블록이 풀리니까 그걸로 쓰레드 외부에서 종료 시키곤 했는데..

ㅡ_ㅡ;

ㅡ,.ㅡ;;의 이미지

쓰레드에서 메모리 할당해놓고 왜 main 에서 해제하는지 의문이군요


----------------------------------------------------------------------------

ctcquatre의 이미지

ㅡ,.ㅡ;; wrote:
쓰레드에서 메모리 할당해놓고 왜 main 에서 해제하는지 의문이군요

흠..스레드는 무한루프 구문입니다.
그리고 스스로 프로그램 종료 상태를 알지 못합니다.

main에서 종료 시그널을 받고 거기에 대한 모든 자원 회수 코드가 실행됩니다.

말씀하신게 다른 방법이나 뜻이 있다면 이야기 해 주시기바랍니다.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

ctcquatre의 이미지

흠 어쩔수 없이 select나 poll을 써야하겠네요.
퍼포먼스를 고려해서 커널 2.6이상일때는 epoll로 가려고 했는데.

이게 취소지점으로 될수없으니.

------ 아 혹시 나중에 모르시는분들 검색할 경우를 위해 -----

select는 취소지점으로 사용될수 있고, poll역시 내부적으로
select를 사용하기때문에 취소지점으로 될수있니다.

------------------------------------------------------

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

alsong의 이미지

pipe를 하나 생성해서 epoll에 포함시키고 메인쓰레드에서 메시지를
날려서 종료하는 방법은 어떤가요.

그리고 select나 poll의 성능을 볼 때 제어문+epoll로 처리하는게 더 효율적일것 같습니다.

그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.

alsong의 이미지

ctcquatre wrote:

"하지만 비교할때마다 pthread_mutex_lock을 호출해야 합니다"

어느부분에서 필요한가요...? 일견 필요없을듯한데...

그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.

ctcquatre의 이미지

alsong wrote:
ctcquatre wrote:

"하지만 비교할때마다 pthread_mutex_lock을 호출해야 합니다"

어느부분에서 필요한가요...? 일견 필요없을듯한데...

스레드에서 비교문을 돌리면
비교대상이 되는 값이 특정 조건일때 값이 바껴야 된다고 하면

스레도 와 스레드 외부에서의 그 비교대상의 값을 바꾸기
위해서 lock이 필요하다고 생각하고, 현제 그렇게 쓰고 있습니다.

아 그리고 pipe는 좀더 뒤져봐야겠네요.
초짜라 잘 모르는게 많습니다 :)
의견 감사합니다. 시원하게 보내세요.

Chaos to Cosmos,
Chaos to Chaos,
Cosmos to Cosmos,
Cosmos to Chaos.

ㅡ,.ㅡ;;의 이미지

ctcquatre wrote:
ㅡ,.ㅡ;; wrote:
쓰레드에서 메모리 할당해놓고 왜 main 에서 해제하는지 의문이군요

흠..스레드는 무한루프 구문입니다.
그리고 스스로 프로그램 종료 상태를 알지 못합니다.

main에서 종료 시그널을 받고 거기에 대한 모든 자원 회수 코드가 실행됩니다.

말씀하신게 다른 방법이나 뜻이 있다면 이야기 해 주시기바랍니다.


쓰레드가 자신이 종료하지 않는다면 도대체 누가 종료시킨다는거지요?


----------------------------------------------------------------------------

tinywolf의 이미지

ㅡ,.ㅡ;; wrote:
ctcquatre wrote:
ㅡ,.ㅡ;; wrote:
쓰레드에서 메모리 할당해놓고 왜 main 에서 해제하는지 의문이군요

흠..스레드는 무한루프 구문입니다.
그리고 스스로 프로그램 종료 상태를 알지 못합니다.

main에서 종료 시그널을 받고 거기에 대한 모든 자원 회수 코드가 실행됩니다.

말씀하신게 다른 방법이나 뜻이 있다면 이야기 해 주시기바랍니다.


쓰레드가 자신이 종료하지 않는다면 도대체 누가 종료시킨다는거지요?

흠.. 그러니까 종료 시점을 쓰레드가 파악할 수 없으니..
(아마도 조건 없이 계속 데이타를 읽거나 쓰는..)
외부에서 판단해서 쓰레드에게 너 종료해라고 알려주는 매커니즘인 것 같습니다.
그리고 메모리 할당을 쓰레드에서 했다면 쓰레드 안에서 종료상태 파악후 루프를 나가서 메모리 해제를 하는 것이 나을 것같네요.
아니면 외부에서 할당하고 해제를 하고 쓰레드는 그 포인터가 사용 가능하다면 루프를 돌고 아니라면 종료하는 방법도..
(<- 제가 자주 쓰는 방법이죠 ㅎㅎ)

ㅡ_ㅡ;

ㅡ,.ㅡ;;의 이미지

tinywolf wrote:
흠.. 그러니까 종료 시점을 쓰레드가 파악할 수 없으니..
(아마도 조건 없이 계속 데이타를 읽거나 쓰는..)
외부에서 판단해서 쓰레드에게 너 종료해라고 알려주는 매커니즘인 것 같습니다.

외부에서 판단해서 쓰레드에게 너종료해 라고 알려준다면 결국 쓰레드가 알수 있다는뜻이군요 그리고 결국 그게 쓰레드 자신이 종료한다는뜻아닌가요?

그리고 도데체 쓰레드에서 main 이나 다른쓰레드가
어떻게 main은 살려두고 일방적으로 다른쓰레드를 죽일수 있냐는겁니다.


----------------------------------------------------------------------------

tinywolf의 이미지

ㅡ,.ㅡ;; wrote:
tinywolf wrote:
흠.. 그러니까 종료 시점을 쓰레드가 파악할 수 없으니..
(아마도 조건 없이 계속 데이타를 읽거나 쓰는..)
외부에서 판단해서 쓰레드에게 너 종료해라고 알려주는 매커니즘인 것 같습니다.

외부에서 판단해서 쓰레드에게 너종료해 라고 알려준다면 결국 쓰레드가 알수 있다는뜻이군요 그리고 결국 그게 쓰레드 자신이 종료한다는뜻아닌가요?

그리고 도데체 쓰레드에서 main 이나 다른쓰레드가
어떻게 main은 살려두고 일방적으로 다른쓰레드를 죽일수 있냐는겁니다.


이글 보고 다시 읽어보니 종료상태를 알 수 없다 이군요..
전 종료시점을 알 수 없다로 잘못봐서.. ㅎㅎ
윈도에서는 쓰레드 핸들가지고 강제로 종료시키는 API가 있었던 것같기도 한데.. 쓸일이 없었기 때문에.. (쓰면 위험한 것 아닌가요? ??)

ㅡ_ㅡ;

익명 사용자의 이미지

문제) 특정한 파라메터에 의해 블록킹됨, IO이벤트외에, 인위적으로 이 블록킹된 상황에서 빠져나오는 방법은?

답변) 당근, 시그널이다. 시그널, 음 SIGUSR1, SIGUSR2등도 있지....
*참고: 시그널은 epoll말고도 임의의 유닉스 시스템 호출중 블록되는 호출에 대해서 무조건 탈출하게 만든다.
음~ 이는 특정한 경우, 좋기도 하지만, 때로 생각못한 상황이 나올 수 있으니, 사려깊게 코딩해야 한다는.....

문제) 쓰레드는 어떻게 죽일까?
답변) 자연스럽게 죽이자.
강제로 죽이지 말고, 스스로 삶을 정리하고 죽게 하는게 쓰레드를 죽이는 좋은 방법중 하나이다.
특정 플래그를 검사하게하고, 그 플래그에 값을 부여함으로써, 해당 쓰레드는
그 값을 감지함과 동시에 자원등을 반납하고, 삶을 정리하고 스스로 죽게 하는것이 좋다.

문제) 그럼 누가 죽으라는 메시지(메시지,플래그세팅등)를 보내는가?
분산환경으로 코딩하면 선출알고리즘이 돌아야하는 아주 어려운 문제가 발생하므로, 역시 단순무식하게 마스터-슬레이브 구조가 좋을 듯하다. 즉, 마스터가 생과사를 총괄하게 한다.
마스터가 죽거나 등으로 유고라면? 시스템페일이지 당근.... 아니면,프로그램이 좀 ~ 어려워지겠지.....

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.