mysql 프로시저 Linux/C/C++ 2012. 11. 7. 20:38

http://blog.naver.com/PostView.nhn?blogId=cache798&logNo=130080151940&categoryNo=68&viewDate=&currentPage=1&listtype=0

1 alarm(TIMEOUT);
2 pause();
3 alarm(0);
..

위와 같이 alarm()을 사용해서 TIMEOUT을 구현하는 경우 race condition 문제가 발생할 가능성이 있다. 1번에서 알람이 설정되고 2번이 실행되기 전에 프로세스 스케줄링이 변경되서 다른 프로세스가 실행되는 경우(서버가 과부하인 상태이고 TIMEOUT이 짧을때), 2번이 실행되기 전에 alarm이 만료되어서 signal을 받을수 있다. 그렇게되면 pause()는 무한정 블럭되어버린다.

이 문제를 해결하는 방법은 몇가지가 있는데 내가 자주 사용하는 방법은 sigsetjmp/siglongjmp를 사용하는 방법이다.

/* SIGALARM handler */
void
sigalrm_handler(int signo)
{
     siglongjmp(jmpbuf, 1);
}

int
main(void)
{
...

       /* SIGALRM에서 사용할 시그널 점프 등록 */
       if(sigsetjmp(jmpbuf, 1) != 0) {
           goto timeout;
       }

       /* 알람 설정 후 신호대기 */
       alarm(TIMEOUT);
       pause();

timeout:
       alarm(0);

...
}

위 코드에서는 SIGALRM이 발생하면 시그널 핸들러를 실행하고 sigsetjmp 위치로 점프한다. 그리고 다시 timeout으로 goto하기 때문에 race condition 상황이 발생해도 pause()는 실행되지 않는다.

'Linux > C/C++' 카테고리의 다른 글

mysql 프로시저  (0) 2012.11.07
Thread와 Signal  (0) 2012.10.19
log file format 조건  (0) 2012.10.19
전처리기 #define do{ 문장1; 문장2; 문장3 }while(0) 사용...  (0) 2012.09.24
UCDParser result to analysis a indexing content  (0) 2012.08.29
Thread와 Signal Linux/C/C++ 2012. 10. 19. 17:59


특정 thread에만 alarm을 사용하고 싶습니다.  signal / 네트워크프로그래밍

2012/05/03 15:27

복사http://blog.naver.com/nds239/10137957769

전용뷰어

출처 : http://rootfriend.tistory.com/161


환경은 1 process, multi-thread라 가정합니다.

그리고 각각의 sub-thread들은 recv 대기중에 있으며 저는 원하는 시간에 이들을 깨우기 위해 alarm()시스템 콜을 사용하려고 합니다.
(time out에서 일반적으로 쓰는 방법, 즉 select 대기나 SO_RCVTIMEO등은 사용할 수 없다고 가정합니다.)

그러나 문제는 alarm이라는 system call이 per-thread가 아닌 per-process라는데 문제가 있습니다.

가령, multi-thread환경에서

alarm(5);
recv(...);
alarm(0);

과 같은 코드를 작성하면 불행하게도 recv에서 대기하고 있던 여러개의 thread가 동시에 wake-up하기 때문에 원하는 바대로 동작할 수 없습니다.

alarm이 아닌 pthread_kill을 사용하는 경우에

pthread_kill(pthread_self(), SIGALRM);
recv(...);

와 같은 Code에서 보듯이 recv에서 대기하는 것이 불가능하게 됩니다.

그래서 결국은 alarm()을 이용하여 SIGALRM을 발생시키면서도 모든 thread가 아닌 특정 thread에서만 SIGALRM을 받을 수 있는 제 3의 방법이 있어야 합니다.

이런 경우를 직접 Coding해 보신 분이 계신지 궁금합니다.

고수의 친절한 가르침을 기대합니다.

===================================================================================================================

일단 multi-thread에서 가장 다루기 힘든 부분 중 하나가 signal 처리입니다. 힘든 건 둘째치고, platform에 따라서 제대로 동작하지 않을 수도 있습니다. 따라서 가능하면 signal을 쓰지 않도록 노력해보기 바랍니다. 그래도 꼭 signal을 써야만 한다면...

pthread_sigmask()를 써서 thread당 독립적으로 동작하는 signal mask를 등록하면 됩니다. 즉 signal을 받고자 하는 thread를 제외한 나머지 thread들에서 해당 signal을 블럭시키면 됩니다. (race condition을 방지하기 위해) thread를 처음 만들 때 자식 thread는 부모 thread로부터 signal mask를 상속받기 때문에, 자식 thread를 여러개 만들기 전에 먼저 블럭시킨다음 thread들을 만들고 나서 원하는 thread에서 unblock시키는 방법을 쓰는 것이 좋습니다.

노파심에서 말하지만 single threaded program에서 같은 목적으로 쓰는 sigprocmask()는 multi threaded program에서 쓰면 안됩니다.

자세한 것은 Programming with POSIX Threads에 잘 나와 있으니 참고하기 바랍니다.

log file format 조건 Linux/C/C++ 2012. 10. 19. 17:40

이번에 어떤 작업을 하면서 
개인적으로 가지고 있던 로그 클래스를 엎었습니다.
지난번에 만들때는 잘 만들었다고 생각했는데 다시 보니 너무 조악하더군요.

다신 만든건 문제가 없는데, 만들다가 느낀게... 별로 대단한 것도 아닌데
프로그래머마다 각자 자기 맘대로 하나씩 가지고 있는 것 같은 느낌이 들더군요,

제대로된 로그 라이브러리가 있으면 그냥 익혀서 쓰면 되는데
또 만든다고 생각하니 시간 낭비 같기도 하고.


일단 개인적으로 필요로 하는 로그 요구 조건은
(1) c++ 클래스 형태로 만들어져 변수가 함수 밖에 보이지 않을 것
(2) win32 함수만 사용해서 다른 의존성 없을 것
     (MFC쓰면 버젼 의존성 발생해서 라이브러리로는 좋지 않음. 그런이유로 VC60 쓰는 회사가 꽤 많음)
(3) 오픈함수open /클로즈 함수 close /출력 함수 print 는 필수
(4) 오픈 함수에서 파일의 생성 유무를 선택할 수 있도록 파라메터 지원 
     (개발자는 필요하지만 사용자는 절대 필요없으므로. 더미 로그를 사용자 PC에 매일 수 메가씩 만든다고 생각라면 끔찍)
(5) 파일을 쓸 폴더가 존재하지 않을 경우 강제로 폴더 만들어 줄 것
(6) 지정한 파일명에 로그 생성 시각을 강제로 포함시켜서 생성할 것
    (같은 이름으로 로그 파일을 만들면 실환경에서 곤란한 상황 벌어짐)  => splitpath 함수 이용하면 구현 가능
(7) 파일에만 출력할 것이 아니라 DebugView.exe도 볼 수 있도록 OutputDebugString도 지원
(8) 출력함수print는 가변인수 지원. 
    (가변인수 지원안하면 알고리즘 코드외에 로그 문장 조합을 위한 불필요한 코드가 생김)
(9) 출력함수print는 매크로로 되어 있어서 __FUNCTION__과 __LINE__을 자동으로 추가해 줄 것
(10) 유니코드 지원

대충 이정도인데, 
로그 출력이 그냥 파일에 텍스트 뿌려대는 것 같지만 실제로 사용하려면 생각보다 까다로운 조건이 많이 붙네요.

네이버나 구글에서 다른 프로그래머가 만든 코드 찾아보면
(1)(3)(7)(8)(9)는 대부분 만족하는데
(2)(4)(5)(6)(10)은 크게 고려되지 않는 것 같네요.
실제 좀 복잡한 상용 제품에 쓸려면 더 복잡해야 할테고.

이번에 새로 구현한 함수 3개
    void OpenFile(LPCWSTR pwszPath, const EN_LVS_KIND enLvsKind);
    void Print(EN_LV_KIND enLvKind, LPWSTR pwszFunction, int nLine, LPWSTR pwszFormat, ...);
    void CloseFile(void);

요약>
좋은 로그 라이브러리 있으면 소개 좀... ^^;

#define catch_exception(ce_arg) fprintf(stdout, "%sn", ce_arg) 

if ( state == -1 ) 
  catch_exception("state is null"); 


위와 같은 코드가 있을때 전처리 과정에 의해 아래와 같은 정상적인 코드로 변환되겠죠? 


if ( state == -1 ) 
  fprintf(stdout, "%sn", "state is null"); 


그런데.. 아래와 같이 define을 사용하였다고 가정합니다. 


#define catch_exception(ce_arg) 
  fprintf(stdout, "%sn", ce_arg); 
  do_something(); 

if ( state == -1 ) 
  catch_exception("state is null"); 


위의 코드는 의도하였던 바와 다르게 아래와 같이 변환됩니다. 


if ( state == -1 ) 
  fprintf(stdout, "%sn", "state is null"); 
  do_something(); 


do_something() 문은 if의 제어를 받지 않게 되는 위치에 놓이게 되겠죠? 
의도한 바에 따른 코드는 아래와 같습니다. 


if ( state == -1 ) 
{ 
  fprintf(stdout, "%sn", "state is null"); 
  do_something(); 
} 


이렇나 경우에  #defines  do { ... } while(0)을 사용하게 됩니다. 


#define catch_exception(ce_arg) 
  do { 
    fprintf(stdout, "%sn", ce_arg); 
    do_something(); 
  while ( 0 ) 


변환된 코드는 아래와 같습니다. 


if ( state == -1 ) 
{ 
  do 
  { 
    fprintf(stdout, "%sn", "state is null"); 
    do_something(); 
  } 
  while ( 0 ); 
} 

또 다른 경우를 살펴보면 아래와 같습니다.

#define exchange(x, y) 
    { int tmp; tmp = x; x = y; y = tmp; } 


익숙한 코드죠? 우선 이러한 매크로가 선언되었습니다. 


if ( x > y ) 
  exchange(x, y); 
else 
  do_something(); 


이 코드는 아래와 같이 변환되겠죠? 


if ( x > y ) 
{ 
  int tmp; 
  tmp = x; 
  x = y; 
  y = tmp; 
} 
; 
else 
  do_something(); 


끝에 세미콜론 하나가 무척이나 거슬림을 넘어서 맘아프게하죠? ^^ㅋ 
이 경우에도  #defines  do { ... } while(0)을 사용하게 됩니다. 


#define exchange(x, y) 
    do { int tmp; tmp = x; x = y; y = tmp; } while ( 0 ) 

if ( x > y )
  exchange(x, y);
else
  do_something();


if ( x > y ) 
  do 
  { 
    int tmp; 
    tmp = x; 
    x = y; 
    y = tmp; 
  } while ( 0 ); 
else 
    do_something(); 




UCD read successed

#########################

Signature = LGUPLUS 

Version = 01.01

SectorUsage = 3

ContentSize = 565135896

#########################

Signature = ZOOINNET

Version   = 01.01

Content Size = 565135896

Content Duration = 491021

Seek Offset = 565135896

Seek Length = 7856

IFR Offset = 565143752

IFR Length = 5073

PAT Offset = 565148825

PAT Length = 188

PMT Offset = 565149013

PMT Length = 188

  • while(fgets(s, MAX_BUFF, file) != NULL)
  • {
  • printf("Printing s: %s\n", s);

  • if(ferror(file))
  • {
  • break;
  • }
  • if(strncmp(s, stock_id, 5) == 0)
  • {
  • printf("Found the stock in %s!\n", argv[1]);
  • break;
  • }
  • }

  • Converting Strings to Numbers.
    ato...() 와 strto...()  부류의 함수들은 문자열을 값으로 변화하기 위해 사용된다. 헤더는 stdlib.h 이다.

    a 는 alpha(또는 ascii) 를 나타내고, str 은 string 을 나타낸다. strto...() 부류는 ato...() 부류에 비해 더 많은 제어와 오류검색을 제공한다.

    ato...() 부류

    atoi()
    오래전부터 정말 많이 쓰이던 함수로, 일명 아토이 함수라고도 불린다. 보통은 a to i 라고 읽는다. i 는 integer를 나타낸다. 문자열을 정수로 변환한다.

    int atoi(const char* );

    숫자가 아닌 문자들은 delimiter로 작용한다. 따라서 초반에 숫자 아닌 문자가 오면 변환이 안된다. 변환이 안될경우 0 을 리턴한다. 단, 문자열 초반의 whitespace 에 대해서는 무시한다.


    예.
    #include<stdio.h>
    #include<stdlib.h>

    int main(void) {
          char str[30];
          scanf("%s",str);
          printf("%d\n",atoi(str));
          return 0;
    }

    사용자 삽입 이미지


    atol()
    atoi() 와 같은데, 다만 변환이 long 형이다.

    long atol(const char* );


    atof()
    이것은 floating-point 특히, double형으로 변환한다.   period (.) 도 소숫점으로 인식한다.

    double atof(const char* );

    다음은 위의 예제 코드와 동일하되, %d 대신 %lf 를 , atoi 대신, atof 를 쓴것이다.


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


    strto...() 부류

    strtol()
    문자열을 long 형으로 변환하고 리턴한다.

    long strtol(const char* , char** , int );

    첫번째 인자는 변환할 대상 문자열이다.

    두번째 인자는 변환이 멈춘 지점의 "포인터의 주소"를 넘겨줄 대상이다. 즉, char** 형 변수가 와야한다. 이것을 NULL 로 설정하면, 멈춘 지점부터 시작하는 문자열을 아무곳에도 저장하지 않는다.

    세번째 인자는 기수법의 밑(base)이다. 2부터 36 까지의 값을 갖는다.
    이 값은 변환할 문자의 범위를 지정하는 것으로, 가령 2 라고 하면, 문자열을 2진법으로 받아들여서 변환한다. 따라서, 0 과 1 만 변환을 수행하고 나머지는 delimiter 가 된다. 또 밑이 10 을 넘는 경우에는... A (또는 a ) 는 10 , B (또는 b ) 는 11 , ... , Z (또는 z) 는 35 과 같은 식으로 변환한다. 이때, 밑에 따라서 받아들이는 값도 그 진법에 맞게 해석된다. 따라서 변환된 값을 10진법으로 출력할 경우, 입력한 스트림과 다른 값이 나오게 된다.

    특히, base를 0 으로 설정하면, 입력한 스트림의 첫부분에 의해 베이스를 8, 16, 10 으로 유연하게 적용할 수 있다. 첫부분이 0x ( 또는 0X ) 이면, base를 16 으로 해석한다. 첫부분이 0x 는 아니면서 0 이면, base를 8 로 해석한다. 나머지 경우는 base 10 으로 해석한다.

    오버플로우 발생시, LONG_VAL 이나 -LONG_VAL 을 리턴하고, ERANGE 가 errno 에 저장된다.

    예.
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>

    int main(void) {
        int base;  long converted;  unsigned i;  char str[30] , *stop;

        printf("Input a string starting with a positive integer : ");      scanf("%s",str);
        printf("Input the base ( 2 ~ 36 ): ");                                 scanf("%d",&base);

        converted = strtol(str,&stop,base);

        for(i=0;i<(strlen(str)-strlen(stop));i++)
              printf("%c",str[i]);

        printf(" (%d)\t->\t%li (10)\n",base,converted);
        return 0;
    }

    실행화면.



    참고로 오류처리 부분만 제외하면...           atol(str)      는    strtol ( str , NULL , 10 )  와 같고,
                                                                atoi(str)     는     (int) strtol ( str , NULL , 10 ) 와 같다.




    strtoul()
    이것은 strtol() 과 유사하지만, unsigned long 을 리턴한다. 오버플로가 발생되면, ULONG_VAL 이나 -ULONG_VAL 이 리턴된다.

    unsigned long strtol(const char* , char** , int );


    strtod()
    이것은  문자열을 double 로 변환한다. 첫번째 인자와 두번째 인자의 의미는 strtol() 과 같다.

    double strtod( const char* , char** );

    오버플로우가 발생되면, HUGE_VAL 이나 -HUGE_VAL 이 리턴되고, 언더플로가 발생되면 0 이 리턴된다. 두경우 모두 ERANGE가 errno 에 저장된다.


    memory lock Linux/C/C++ 2012. 7. 16. 10:31

    int mlock (const void *addr, size_t  len)

    int mlockall (int flags)

    int munlock(const void *addr, size_t len) 페이지 잠금 호출은 스택되지 않기 때문에 한번 같은 메모리 주소에 대해 여러 번 잠금 호출되었다고 하더라도 잠금을 해제할 때는 한번만 해주면 됨, 잠금 해제하는 메모리 범위에 포함된 모든 페이지들은 같이 잠금이 해제됨

    int munlockall (void)


    * 페이지 잠금은 fork에 의해 상속 받지 않는다


    페이지 잠금 호출 :

    int mlock (const void *addr, size_t  len)

    int mlockall (int flags)


    해제 호출 :

    int munloock(const void *addr, size_t len)

    int munlockall (void)


    int mlock (const void *addr, size_t  len)

    지정 된 메모리 주소 addr로 부터 len 길이만큼 페이징 금지

    int mlockall (int flags)

    해당 프로세스의 모든 메모리의 페이징을 금지하고, flag에 두 개의 지정 가능한 이수를 가짐

    - MCL_CURRENT 현재 상태에서의 프로세스에 대응된 모든 페이지를 잠근다.

    - MCL_FUTURE 앞으로 발생하는 모든 대응된 페이지를 잠근다. ( 새로운 메모리맵, 공유 메모리, 힙, 스택 모두에 대해서 적용된다 )


    선형 검색

    (Liner Search) : lsearch(3), lfind(3)

    이진 검색

    (Binary Search) : qsort(3), bsearch(3)

    해시 검색

    (hash search) : hcreate(3), hsearch(3), hdestroy(3)

    트리 검색

    (tree search) : tsearch(3), tfind(3), twalk(3), tdelete(3)