티스토리 뷰

IT/OS

Reentrant -

NineKY 2007. 12. 18. 09:50

Introduction

  • pthread 를 이용한다면 한번쯤 Reentrant function 에 대하여 들어보았을 것이다. 간단하게 Reentrant 에 대해서 적어본다.

Detailed Description

  • reentrant function이 중요하게 되는 경우는 signal handler에서 사용가능하느냐와 multi-thread 환경에서 입니다. 어떤 function이 전역변수를 사용하거나 static 변수를 사용한다고 할때, 한 process가 이 function에 진입하여 실행중에 signal이 발생하고 signal handler에서 다시 이 function에 진입한다면 예기치 않은 결과를 얻을 수 있습니다. 마찬가지로 동일 process의 서로다른 thread가 같은 function에 진입하는 경우도 문제가 될 수 있습니다. 그래서 reentrant function은 (1)전역변수 사용안함 (2)static 변수 사용안함 (3)stack 변수만 사용 으로 보장됩니다. 조금 다른 개념으로 thread-safe function이라는 개념도 있는데, 이는 reentrant function이거나 그렇지 않은 경우라면 mutex등을 사용하여 전역변수에 대한 동시접근을 막아서 multi-thread 환경에서 안전함을 보장합니다. thread-safe function이지만 reentrant function이 아닌 경우라면 signal handler에서의 사용은 금지됩니다.

int no_reentrant_counter( int increment) 
{ 
    static my_counter=0; 
    my_counter= mycounter + increment; 
    return my_counter; 
} 

int reentrant_counter(int current, int increment) 
{ 
    return current; 
} 

함수 내부 변수를 스태틱으로 사용하면 (또는 외부에 전역변수로 사용하면) 사실 편리할 때가 많습니다. 
하지만 여러 함수에서 동시에 부르는 (스케줄링에 따라 말이죠) 상황이면 결과가 틀릴 수가 있습니다. 

예를 들면 쓰레드 프로그램에서 no_reentrant_counter(1)을 두부분이 사용한다 치면 
한부분에서 호출하고 우연히 함수콜 한 다음에 블럭 되어버려서 
다른 부분에서 호출하는 부분으로 넘어갈 수도 있습니다. 
그당시 my_counter가 10이었다면 
(1)번 (2)번이 부른다 치면 
* (1) -> no_reentrant 호출 
* my_counter= mycounter + 1; 수행도중 
>> mycounter+1=11로 계산했고 막 mycounter에 11을 넣으려다 블럭됨
 (한줄에 썼지만 몇단계로 나뉘어 실행되죠. 값 읽어오고, 계산하고, 결과 저장하고) 
@ (2) -> no_reentrant 호출하였음 
@ 아직 my_counter를 11로 못 바꾼 상태이므로 10이었던 것으로 계산해서 
@ my_counter= 10+1; ===>11 
@ my_counter <=11 후 리턴 
* (1)로 다시 돌아가서 
* 아까 하던 일 마저하기 (my_counter에 11 넣기) 
결국 최종값은 11이 되죠. 두번 호출했으니 12가 되어야 하는데 말이죠. 
그래서 쓰레드 돌리며 값을 바꾸는 것과 같이 동기화가 필요한 데에서는 
reentrant함수를 사용해야 합니다. 

ps. 사실 예로 든게 아주 적절하진 않습니다. reentrant_counter도 저렇게는 
써봤자 mutex나 semaphore를 써야 되지만.. 어쨌든 reentrant하지 않으면 
결과 값이 이상해 지는 경우도 있구나 하고 생각하시면 됩니다. 
꼭 reentrant 해야 하는 함수로 printf가 있죠. 여러 곳에서 동시에 
호출하는 데 내부 스태틱 변수 같은 것을 쓴다 치면.. 대란이 일어나겠죠.
  • thread-safe function 은 말 그대로 multi-thread환경에서 여러 thread가 동시에 동일 함수에 진입했을 때 안전한 function 입니다. 저번에도 말씀드렸듯이 thread-safe function은 reentrant function 이거나, reentrant function이 아니라면 mutex 등으로 전역변수에의 동시 접근을 막아서 여러 thread가 동일 함수에 동시에 진입했을때 안전함을 보장하는 function 입니다. reentrant function은 내부적으로도 동기화를 위한 locking처리 자체를 하지 않습니다. 동기화 할 필요가 없도록 function을 설계하는 것이지요. 하지만 어쩔수 없이 전역변수를 사용해야 하는 function이 있을 수 있겠지요? 이런 function이라면 여러 thread가 동시에 접근하는 경우에 대비해 전역변수를 사용하는 code 부분을 mutex 등으로 막아서 여러 thread가 동시에 function에 진입할 수는 있으나 동시에 전역변수에 접근하지는 못하도록 합니다. 이런 경우 동일 process/thread context에서 signal이 발생하여 signalhandler에서 이 함수에 다시 진입한다면 dead lock 이 발생할 수 있습니다. 그렇기 때문에 reentrant 하지 않은 thread-safe function은 signal handler에서 사용하지 않습니다. 결국 어떤 function이 reentrant function 이라면 당연히 thread-safe function입니다. 하지만 모든 thread-safe function이 reentrant function 인 것은 아닙니다.
  • 부언하여 -D_REENTRANT 를 제가 아는 한도에서 설명드리자면, 선언이 되면, 대개의 구현에서.. include 할 때, _r 계열 함수의 선언을 열어 주는(?) 것과 기존 함수 혹은 변수를 reentrant 계열로 재정의해주게 됩니다. 즉, 함수가 두 벌이 존재하고, -D_REENTRANT 에 따라 link 되는 것이 달라지게 됩니다. 그리고, 대개의 구현에서 내부에 static 값이 있는 경우에 대해 pthread_key_create 시리즈 함수를 사용하여 thread 만의 데이터를 핸들링하도록 합니다.
  • 그렇다면 -D_REENTRANT 을 선언해 주어야 하는 것일까? 혹자는 쓰레드 라이브러리를 사용하게 되면 -D_REENTRANT 가 자동 선언된다고 하는데 아닌 것 같기도 하고..???

Reference


CategoryCpp

검색어: thread reentrant

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함