« Previous : 1 : ... 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : ... 33 : Next »

Sybase 날짜형(datetime)의 문자열 변환시 style number

select convert(varchar,날짜데이터, convertType) 형식으로 쓰고 convertType 위치에 숫자가  들어갈 때 옆에 적힌 형식대로 나온다고 보시면 됩니다.


Style number

  • 0 = Aug 27 2007  5:28PM
  • 1 = 08/27/07
  • 2 = 07.08.27
  • 3 = 27/08/07
  • 4 = 27.08.07
  • 5 = 27-08-07
  • 6 = 27 Aug 07
  • 7 = Aug 27, 07
  • 8 = 17:23:35
  • 9 = Aug 27 2007  5:28:08:563PM
  • 10 = 08-27-07
  • 11 = 07/08/27
  • 12 = 070827
  • 13 = 07/27/08
  • 14 = 08/07/27
  • 15 = 27/07/08
  • 16 = Aug 23 2007 17:28:08
  • 18 = 15:17:08
  • 19 = 5:11:39:086PM            
  • 20 = 17:12:30:633
  • 21 = 07/08/27
  • 22 = 07/08/27
  • 100 = Aug 27 2007  5:28PM
  • 101 = 08/27/2007
  • 102 = 2007.08.07
  • 103 = 27/08/2007
  • 104 = 27.08.2007
  • 105 = 27-08-2007
  • 106 = 27 Aug 2007
  • 107 = Aug 27, 2007
  • 108 = 17:28:08
  • 109 = Aug 27 2007 5:28:08:563PM
  • 110 = 08-27-2007
  • 111 = 2007/08/27
  • 112 = 20070827
  • 113 = 2007/27/08
  • 114 = 08/2007/27
  • 115 = 27/2007/08
  • 116 = Aug 23 2007 17:28:08


응용

select convert(char,GETDATE(),112)
:오늘날짜를 YYYYMMDD로

select convert(char(8), DATEADD(DD,-1,getdate()) ,112)  
:현재 날짜 하루전을 yymmdd형식으로 출력


select convert(char(8), DATEADD(DD,-1,'20070827') ,112)  
: 2007년 8월 27일 전날을 출력. string -> datetime은 convert라는 함수를 사용하지 않고 내부적(implicit)으로 자동으로 변경


select str_replace( convert(varchar,getdate(),20),':',null)

: 현재 분일초,밀리세컨드까지: 152515853


select convert(varchar,GETDATE(),112) || str_replace( convert(varchar,getdate(),20),':',null)

: 현재 연월일시분초밀리세컨드

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Posted by 소리나는연탄.

Leave your greetings here.

  
  
  
  
  
  
  
  
 

리눅스 한글처리

2008/01/30 16:20 / Resource

한글처리

Contents

1 한글처리
1.1 개요
1.2 조합형
1.2.1 한글코드 (조합형)
1.2.1.1 코드표 (조합형: 삼보, 대우, 현대, 쌍용, 큐닉스)
1.2.1.2 벌수 구성표
1.3 문서를 마치면서
1.4 저작권

  • 작성자 : 조재혁 (Mminzkn_at_infoeq.com)

    1.1 개요

    한국 사람이 한국어를 구현못한다면 낭패다.
    한글의 구조 및 공통점을 찾지 못하는 것도 낭패다.
    적어도 한국사람이라면 한글구현은 한번쯤 겪어보는게 좋다.
    물론 필자 역시 리눅스용으로 한글을 구현해서 공개하려고 했다. 하지만 그리 쉽지만은 않다.
    또한 한글출력은 그나마 쉽다. 하지만 중요한 문제는 한글오토마타의 구현이다.
    여러분들은 오토마타를 우습게 보지 말아야 한다. 구현해보면 알게 된다. 그 어려운 산을 넘는 법을 말이다.

    1.2 조합형

    조합형은 초성, 중성, 종성을 각각 폰트로 본다는 점에서 완성형과 다르다.
    또한 완성형과 비교하면 폰트의 크기가 보통 훨씬 작다.

    1.2.1 한글코드 (조합형)

    1.2.1.1 코드표 (조합형: 삼보, 대우, 현대, 쌍용, 큐닉스)

    • 밑의 테이블은 한글구현에 있어서 필수사항이다. 외우는것이 좋다. 외우자! 무조건.
    • 순번은 어디다가 쓰길래 적어놓았냐는 의문은 갖지 말자. 만들어보면 안다. 왜 있어야 했는지.
      비트조합 (bit) 10진 코드 16진 코드 초성(순번) 중성(순번) 종성(순번)
      0 0 0 0 0 0 00 미정의 미정의 미정의
      0 0 0 0 1 1 01 채움 미정의 채움
      0 0 0 1 0 2 02 ㄱ (0x00) 채움 ㄱ (0x00)
      0 0 0 1 1 3 03 ㄲ (0x01) ㅏ (0x00) ㄲ (0x01)
      0 0 1 0 0 4 04 ㄴ (0x02) ㅐ (0x01) ㄳ (0x02)
      0 0 1 0 1 5 05 ㄷ (0x03) ㅑ (0x02) ㄴ (0x03)
      0 0 1 1 0 6 06 ㄸ (0x04) ㅒ (0x03) ㄵ (0x04)
      0 0 1 1 1 7 07 ㄹ (0x05) ㅓ (0x04) ㄶ (0x05)
      0 1 0 0 0 8 08 ㅁ (0x06) 미정의 ㄷ (0x06)
      0 1 0 0 1 9 09 ㅂ (0x07) 미정의 ㄹ (0x07)
      0 1 0 1 0 10 0A ㅃ (0x08) ㅔ (0x05) ㄺ (0x08)
      0 1 0 1 1 11 0B ㅅ (0x09) ㅕ (0x06) ㄻ (0x09)
      0 1 1 0 0 12 0C ㅆ (0x0a) ㅖ (0x07) ㄼ (0x0a)
      0 1 1 0 1 13 0D ㅇ (0x0b) ㅗ (0x08) ㄽ (0x0b)
      0 1 1 1 0 14 0E ㅈ (0x0c) ㅘ (0x09) ㄾ (0x0c)
      0 1 1 1 1 15 0F ㅉ (0x0d) ㅙ (0x0a) ㄿ (0x0d)
      1 0 0 0 0 16 10 ㅊ (0x0e) 미정의 ㅀ (0x0e)
      1 0 0 0 1 17 11 ㅋ (0x0f) 미정의 ㅁ (0x0f)
      1 0 0 1 0 18 12 ㅌ (0x10) ㅚ (0x0b) 미정의
      1 0 0 1 1 19 13 ㅍ (0x11) ㅛ (0x0c) ㅂ (0x10)
      1 0 1 0 0 20 14 ㅎ (0x12) ㅜ (0x0d) ㅄ (0x11)
      1 0 1 0 1 21 15 미정의 ㅝ (0x0e) ㅅ (0x12)
      1 0 1 1 0 22 16 미정의 ㅞ (0x0f) ㅆ (0x13)
      1 0 1 1 1 23 17 미정의 ㅟ (0x10) ㅇ (0x14)
      1 1 0 0 0 24 18 미정의 미정의 ㅈ (0x15)
      1 1 0 0 1 25 19 미정의 미정의 ㅊ (0x16)
      1 1 0 1 0 26 1A 미정의 ㅠ (0x11) ㅋ (0x17)
      1 1 0 1 1 27 1B 미정의 ㅡ (0x12) ㅌ (0x18)
      1 1 1 0 0 28 1C 미정의 ㅢ (0x13) ㅍ (0x19)
      1 1 1 0 1 29 1D 미정의 ㅣ (0x14) ㅎ (0x1a)
      1 1 1 1 0 30 1E 미정의 미정의 미정의
      1 1 1 1 1 31 1F 미정의 미정의 미정의

    1.2.1.2 벌수 구성표

    • "왜 벌수가 필요한가?" 질문하신다면 저는 "예뻐보이라고요" 라고 답하겠습니다.
    • 초성은 6벌, 중성은 10벌, 종성은 4벌로 기본적인 벌수가 구성된다. 하지만 일부 폰트는 크기를 줄이고자 각 1벌씩만 가지는 경우가 있다.
    • 어떤 폰트는 좀더 모양새를 완전하게 하기 위해서 예외 벌이 들어 있다. 하지만 그것을 구현할 이유는 별로 없어보인다.
    • 초성
      벌수 초성의 종류 중성 사용의 예
      종성채움 1 초성이 'ㄱ', 'ㅋ'일 때 '가', '고', '크', '커', ...
      종성채움 2 초성이 'ㅎ'일 때 '하', '혀', '효', ...
      종성채움 3 1, 2벌이 아닌 경우의 나머지 '배', '마', '나', '다', ...
      종성코드 4 초성이 'ㄱ', 'ㅋ'일 때 '각', '곡', '클', '컽', '켞', ...
      종성코드 5 초성이 'ㅎ'일 때 '한', '형', '혼', ...
      종성코드 6 1, 2벌이 아닌 경우의 나머지 '백', '막', '낙', '독', ...
    • 중성
      벌수 중성의 종류 초성 사용의 예
      종성채움 1 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅣ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ' '가', '개', '갸', '걔', '기', ...
      종성채움 2 'ㅗ', 'ㅛ', 'ㅡ' '고', '교', '그', ...
      종성채움 3 'ㅜ', 'ㅠ' '구', '규', ...
      종성채움 4 'ㅘ', 'ㅙ', 'ㅚ', 'ㅢ' '과', '괘', '괴', '긔', ...
      종성채움 5 'ㅝ', 'ㅞ', 'ㅟ' '궈', '궤', '귀', ...
      종성코드 6 'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅣ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ' '각', '객', '갹', '걕', '긱', ...
      종성코드 7 'ㅗ', 'ㅛ', 'ㅡ' '곡', '굑', '극', ...
      종성코드 8 'ㅜ', 'ㅠ' '국', '귝', ...
      종성코드 9 'ㅘ', 'ㅙ', 'ㅚ', 'ㅢ' '곽', '괙', '괵', '긕', ...
      종성코드 10 'ㅝ', 'ㅞ', 'ㅟ' '궉', '궥', '귁', ...
    • 종성
      벌수 중성의 종류 종성 사용의 예
      1 'ㅏ', 'ㅑ', 'ㅘ', 'ㅣ'의 중성이 있는 경우 '각', '얇', '인', ...
      2 'ㅓ', 'ㅕ', 'ㅚ', 'ㅝ', 'ㅟ', 'ㅢ'의 중성이 있는 경우 '건', '격', '원', '윈', '벽', ...
      3 'ㅐ', 'ㅒ', 'ㅔ', 'ㅖ', 'ㅙ', ㅞ'의 중성이 있는 경우 '객', '액', '왠', '췔', ...
      4 'ㅗ', 'ㅛ', 'ㅜ', 'ㅠ', 'ㅡ'의 중성이 있는 경우 '곡', '욕', '음', '흠', ...

    1.3 문서를 마치면서

    • 이 문서에서 틀린 부분이나 고쳐야 할부분이 있으면 꼭 알려주십시요.

    1.4 저작권

    • 본 문서는 [http]GFDL의 라이센스를 기반으로 작성되었고 유지됩니다.

    출처 : 조인 위키

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Posted by 소리나는연탄.

Leave your greetings here.

  
  
  
  
  
  
  
  
 

Contents

1 소개
2 시나리오
3 구현방안
3.1 메시지큐 구현
3.1.1 worker Thread 관리
3.1.2 쓰레드 동기화
3.1.3 프로시져
3.1.4 코드 구현
4 공유메모리 구현

1 소개

쓰레드 프로그래밍을 할 때 가장 신경쓰이는건 역시 쓰레드동기화와 쓰레드간 메시지 전달과 관련된 문제일 것이다. 또한 쓰레드간 메시지 전달에는 쓰레드 동기화 문제까지 함께 고민해야 한다. 이 문서는 다중쓰레드에서 쓰레드간 메시지를 효과적으로 전달하기 위한 다양한 방법들을 기술한다.

여기에서 소개하는 방법들은 수많은 방법들 중 몇가지 방법들일 뿐이다. 실제 프로젝트에서는 다양한 응용을 생각해야 할 것이다.

2 시나리오

영어문서를 파싱해서 Term을 얻어오고, 출현한 Term의 빈도수를 계수하는 프로그램을 만들도록 하겠다. 빠른 파싱을 위해서, 문서가 주어지면 문서를 라인수를 기준으로 4등분 한다음, 4개의 쓰레드를 돌려서 병렬로 처리하도록 할 것이다. 이 프로그램은 다음의 사항을 만족시켜야 한다.
  1. Main 쓰레드는 문서를 4등분한다음 생성된 work thread갯수를 파악한다음
  2. 파일을 open()한 후, 4개의 쓰레드에게 읽어야될 파일지정자와 파싱할 줄의 범위를 알려준다.
  3. 파일지정자와 범위를 전달받은 work thread는 해당범위의 문장을 분석해서 <Term, count> 자료구조를 만든다.
  4. 모든 작업이 끝났다면, Main Thread에게 작업이 끝났음을 알려준다. 이때, 자신이 작업한 결과에 대한 정보를 Main Thread에게 알려줘야 한다.
  5. 모든 work Thread에서 작업종료 메시지를 받았다면, Main Thread는 각 work Thread의 <Term, count>를 취합해서, 하나의 파일로 만든다.

3 구현방안

다음은 문서를 파싱해서 <Term, count>를 얻어오는 프로그램이다. 단일 쓰레드로 작동하는 프로토타입의 프로그램으로 아래의 코드를 멀티쓰레드방식으로 수정할 것이다.

#include <sys/types.h> 
#include <regex.h> 
#include <string.h> 
#include <stdio.h> 
#include <errno.h> 
#include <vector> 
#include <string> 
#include <iostream> 
 
#include <fcntl.h> 
 
using namespace std; 
 
/* 
 * 주어진 문서에서 단어를 얻어온다. 
 * 입력된 라인은 strtok를 통해서 토큰으로 먼저 분리되고 
 * 분리된 문자열은 정규표현을 만족하면 Term으로 판단하고 출력한다. 
 * 실행인자 : 정규표현식 
 * 사 용 예 : 
 */ 
 
int main(int argc, char **argv) 
{ 
  FILE *fp; 
  int rtv; 
  regex_t preg; 
  char linebuf[1024]; 
  char *tr; 
  char seps[] = " -.,()\";:{}'+@/<>[]|!?#"; 
  char msg[64]; 
  int i; 
  vector<string> FileList; 
 
  // 파싱할 파일을 등록한다. 
  FileList.push_back("rfc.dat"); 
 
  if (argc != 2) 
  { 
    printf("Usage : %s [pattern]\n", argv[0]); 
    return 1; 
  } 
 
  // 정규표현을 위한 컴파일러 생성 
  rtv = regcomp(&preg, argv[1], REG_EXTENDED|REG_NOSUB); 
  if(rtv != 0) 
  { 
    regerror(rtv, &preg, NULL, 0); 
    return 1; 
  } 
 
  for(int i = 0; i < FileList.size(); i++) 
  { 
    fp = fopen(FileList.c_str(), "r"); 
    if (fp == NULL) 
    { 
      perror("Error "); 
      return 1; 
    } 
 
    while(fgets(linebuf, 1024, fp) != NULL) 
    { 
      linebuf[strlen(linebuf)-1] = '\0'; 
 
      // 토큰으로 구분한다음 
      tr = strtok(linebuf, seps); 
      while(tr != NULL) 
      { 
        tr = strtok(NULL, seps); 
        if (tr != NULL) 
        { 
          // 정규표현을 만족하는지 확인한다. 
          if (regexec(&preg, tr, 0, NULL, 0) == 0) 
          { 
            cout << "Find Term : " << tr << endl; 
          } 
        } 
      } 
    } 
    fclose(fp); 
  } 
} 
 
다음과 같이 실행하면 된다.
# ./getterm "[a-zA-Z0-9]" 
 

3.1 메시지큐 구현

메시지큐 구현에 대한 아이디어는 다음과 같다.
  • worker Thread가 하나의 Term을 얻어오면, 해당 Term을 메시지 형태로 Main Thread에게 바로 전달한다.
  • Main Thread는 <Term, count>자료구조를 유지하면서, 계수를 한다.
  • 메시지큐의 ID는 하나로 통일한다.
  • 메시지큐를 이용한 메시지의 전달 가능성 확인을 목적으로 한다.(병렬성 효율등은 부차적 문제로 언급한다)

사용자 삽입 이미지



3.1.1 worker Thread 관리

주고 받는 데이터에 타입을 두어서 관리하도록 할 것이다.
struct Data 
{ 
    int type; 
    char *Data; 
    int size; 
}; 
 
Type는 다음과 같이 정의 할 것이다.
1 << 1 일반 데이터
1 << 2 제어 데이터
  • 일반데이터라면 Data를 파싱된 Term으로 인식해서 처리한다.
  • 제어데이터라면 Data를 제어 명령이라고 인식해서 처리한다. Data가 1 이라면, 모든 일을 끝냈다고 판단한다.

이 방식은 구현이 단순하긴 하지만 worker thread -> Main thread로의 단방향 데이터 전송만 가능하다는 단점이 있다. 메시지큐를 하나더 만드는등 다양한 방법이 있을 수 있는데, 이는 뒤에서(몇가지만) 다루도록 하겠다.

3.1.2 쓰레드 동기화

쓰레드간 동기화는 mutex 잠금과 조건변수를 이용할 것이다.

3.1.3 프로시져

대충 그림을 그려야 코드가 만들어 지는 스타일이라서...
main 
{ 
    생성 쓰레드 갯수는 4개로 한다. 
    문서를 읽어들여서 문서의 Line수를 계수한다. 
    메시지큐를 생성한다. 
    for(i = 0; i < 4; i++) 
    { 
        // 쓰레드 동기화 Start 
        Worker 쓰레드를 생성한다. 인자로 문서의 Offset정보를 넘긴다. 
        쓰레드 함수명은 WThread로 한다.  
        // 쓰레드 동기화 End  
    } 
    메인 쓰레드를 수행한다. 
    while(1) 
    { 
        메시지 큐로부터 데이터를 읽는다. 
        switch(데이터 타입) 
        case 일반데이터 
        { 
            Term을 계수한다. 
        } 
        case 제어데이터 
        { 
            종료루틴을 수행한다. 
            모든 쓰레드가 작업을 종료했다면, Break;  
        } 
    } 
    <Term,Count>결과를 출력한다. 
} 
 

3.1.4 코드 구현

<!> 미완성 코드다. g++ 로 컴파일 하면, 메시지큐를 통해서 worker thread에서 main thread로 분석된 Term이 전달되는걸 확인할 수 있다. 메시지큐를 통한 데이터 통신의 기본적인 구현은 끝났다고 볼 수 있다. 코드를 좀더 깔끔하게 하고, 몇 군데 예외처리를 해주어야 한다.
#include <pthread.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
#include <sys/stat.h> 
#include <regex.h> 
 
#include <fcntl.h> 
#include <string.h> 
 
#define ThreadNum 4 
 
pthread_mutex_t mutex_lock; 
pthread_cond_t  sync_cond; 
 
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t  gcond  = PTHREAD_COND_INITIALIZER; 
 
const char seps[] = " -.,()\";:{}'+@/<>[]|!?#\n"; // Token 
 
// 주고 받을 데이터 
struct Data 
{ 
    int queuenum; 
    int msgtype;  
    int tid; 
    char msg[256]; 
    int size; 
    key_t key_id; 
}; 
 
// worker 쓰레드에 넘겨줄 정보 
struct DocInfo 
{ 
    int tnum;       // thread id 
    int start;      // 문서시작 위치 
    int end;        // 문서 끝 위치 
    char fname[80]; // 작업 파일명 
    char regex[24]; // 정규표현 문자열  
}; 
 
/* 
 * worker 쓰레드 함수 
 */ 
void *Tfunction(void *data) 
{ 
    struct Data lData; 
    struct DocInfo *lDocInfo;  
    FILE *fp; 
    char line[256]; 
    int rtv; 
    int bsize; 
    int readn = 0; 
  regex_t preg; 
  char *tr; 
 
    lData = *(struct Data *)(data); 
    lDocInfo = (struct DocInfo *)lData.msg;  
 
    bsize = lDocInfo->end - lDocInfo->start; 
    printf("DEBUG Thread %d %d\n", lDocInfo->tnum, bsize); 
    if((fp = fopen(lDocInfo->fname, "r")) == NULL) 
    { 
        perror("Fopen Error"); 
        exit(0); 
    } 
 
    lseek(fileno(fp), lDocInfo->start, SEEK_SET);     
  rtv = regcomp(&preg, lDocInfo->regex, REG_EXTENDED|REG_NOSUB); 
 
    pthread_mutex_lock(&mutex_lock); 
    pthread_cond_signal(&sync_cond); 
    pthread_mutex_unlock(&mutex_lock); 
 
    if (rtv != 0) 
    { 
        regerror(rtv, &preg, lDocInfo->regex, REG_EXTENDED|REG_NOSUB); 
        exit(0); 
    } 
    for (readn = 0; readn < bsize; ) 
    { 
        if(fgets(line, 256, fp) == NULL) 
            break; 
        tr = strtok(line, seps); 
        if (tr != NULL) 
        { 
            if (regexec(&preg, tr, 0, NULL, 0) == 0) 
            { 
                lData.queuenum = 1; 
                lData.msgtype = 1 << 1; 
                lData.size = strlen(tr); 
                sprintf(lData.msg, "%s", tr); 
 
                if(msgsnd(lData.key_id, (void *)&lData, sizeof(lData), IPC_NOWAIT) <0) 
                { 
                    perror("msg snd error"); 
                    exit(0); 
                } 
            } 
        } 
        readn += strlen(line); 
        sleep(1); 
    } 
    // 종료 메시지를 보낸다. 
} 
 
 
int main(int argc, char **argv) 
{ 
    struct Data lData; 
    struct DocInfo lDocInfo;  
 
    pthread_t p_thread[ThreadNum]; 
 
    int fd; 
    char *fname; 
    int fsize = 0; 
    int blocksize = 0; 
    struct stat fileinfo; 
    char *regex; 
 
    // Message queue 
    key_t key_id; 
    int msgtype;     
 
    fname = argv[1]; 
    regex =  argv[2]; 
 
    // 메시지큐 생성 
    key_id = msgget((key_t)8888, IPC_CREAT|0666); 
    if (key_id == -1) 
    { 
        perror("msgget error : "); 
        exit(0); 
    } 
 
    // Open File 
    fd = open(fname, O_RDONLY);     
    if (fd < 0) 
    { 
        perror("Open file error"); 
        return 1; 
    } 
    if(fstat(fd, &fileinfo)< 0)  
    { 
        return 1; 
    } 
    fsize = fileinfo.st_size; 
    printf("T Size is %d\n", fsize); 
 
    blocksize =  fsize / ThreadNum;  
 
    for (int i = 0; i < ThreadNum; i++) 
    { 
        lDocInfo.start = (i*blocksize); 
        lDocInfo.end = lDocInfo.start+blocksize; 
        sprintf(lDocInfo.fname, "%s", fname); 
        sprintf(lDocInfo.regex, "%s", regex); 
        lDocInfo.tnum = i; 
 
        if (i == (ThreadNum -1)) 
            lDocInfo.end += fsize%ThreadNum; 
        lData.queuenum = 1;  
        lData.msgtype = 1 << 2;  
        lData.size = sizeof(lDocInfo);  
        lData.key_id = key_id; 
        lData.tid = lDocInfo.tnum;  
        memcpy((void *)lData.msg, (void *)&lDocInfo, sizeof(lDocInfo)); 
 
        pthread_mutex_lock(&mutex_lock); 
        pthread_create(&p_thread, NULL, Tfunction, (void *)&lData); 
        pthread_cond_wait(&sync_cond, &mutex_lock); 
        pthread_mutex_unlock(&mutex_lock); 
    } 
 
    while(1) 
    { 
        if(msgrcv(key_id, (void *)&lData, sizeof(lData), (1 >> 1), 0)    == -1) 
        { 
            perror("msgrcv error: "); 
        } 
        printf("Get Term %d %s\n", lData.tid, lData.msg); 
    } 
} 
 

4 공유메모리 구현

공유메모리는 커널에 메모리 공간을 할당함으로써, 시스템 전역적으로 자원을 사용할 수 있도록 지원하는 IPC 설비중 하나다. 이러한 특성을 이용 쓰레드간 메시지 교환은 공유메모리상에 환형큐를 만드는 것으로 구현가능할 수 있을 것이다.

이 환형큐에는 여러개의 쓰레드가 접근을 하게 될 것이므로, 쓰레드간 동기화가 필수 적일건데, mutex가 아닌 레코드 잠금으로도 쓰레드간 접근제어를 할 수 있다. 레코드 잠금을 통해서 쓰레드동기화를 제어하는 방법은 공유메모리와 파일잠금을 이용한 프로세스간 데이터 공유에서 이미 다룬바가 있다.

쓸만한 예제라고 생각은 하지만 이번 구현에 그대로 적용하기에는 성격이 다르다. 이번 구현은 여러개의 생산자와 하나의 소비자가 존재하는 형식이기 때문이다. 뭐 그렇다고 크게 문제될건 없다. 아래와 같이 생산/소비자 방식을 약간 수정하는 것으로 해결책을 삼았다.
사용자 삽입 이미지


쓰레드간 동기화는 그대로 파일의 레코드 잠금을 이용할 것이다. 이 경우 다수의 생산자를 제어해야 하는데, 처음 8 byte를 생산자간 접근제어를 위한 잠금으로 사용할 것이다. 처음 레코드에 대한 생산자만이 레코드에 큐(빨간색)에 쓸권한을 가지게 된다.

데이터 쓰기 권한을 얻은 쓰레드는 공유메모리에 데이터를 쓰고, 해당 공유메모리에 대응되는 레코드에 잠금을 풀게된다. 그러면 소비자는 잠금을 얻고, 잠금에 대응되는 공유메모리를 찾아가서 정보를 읽어오면 된다. 예제로 제시한 문서를 이해하고 있다면, 위의 방식으로 수정하는건 그리 어렵지 않을 것이니, 굳이 코드를 만들진 않도록 하겠다.

출처 : 조인시 위키
크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Posted by 소리나는연탄.

Leave your greetings here.

  
  
  
  
  
  
  
  
 

Contents

1 메시지 큐란
2 메시지큐의 생성, 사용, 제어
3 메시지큐 생성
4 메시지큐에 데이타 쓰기
5 메시지큐의 데이타 가져오기
6 예제를 통해 알아본 메시지큐
7 메시지큐의 제어
8 정리
9 참고문서

1 메시지 큐란

메시지큐는 메시지를 queue 데이타 구조 형태로 관리한다. 는 선입선출(먼저 들어간게 먼저 나오는) 데이타 구조를 말하며, 보통의 은행창구 혹은 일반적인 줄서기를 생각하면 된다. 이것은 흔히 FIFO(First in First Out)라고 불리운다(IPC 의 FIFO 설비와 혼동하지 말자). 이것과 반대되는 데이타 구조를 stack 이라고 하며, 큐와 반대로 가장 나중에 들어온게(가장 최근데이타) 먼저 나오는 형태를 가진다.

일반적인 배열을 접근방법에 따라 특수하게 분류한것이라고 생각하기 바란다.

메시지큐는 커널에서 전역적으로 관리되며(이를테면 커널 전역변수형태로), 모든 프로세스에서 접근가능하도록 되어있으므로, 하나의 메시지큐 서버가 커널에 요청해서 메시지큐를 작성하게 되면, 메시지큐의 접근자(식별자)를 아는 모든 프로세서는 동일한 메시지큐에 접근함으로써, 데이타를 공유할수 있게 된다.

메시지큐의 IPC로써의 특징은 다른 공유방식에 비해서 사용방법이 매우 직관적이고 간단하다라는데 있다. 다른 코드의 수정없이 단지 몇줄만의 코드를 추가시킴으로써 간단하게 메시지큐에 접근할수 있다.

또한 뒤에서 자세히 다루겠지만 메시지의 type 에 의해서 여러종류의 메시지를 효과적으로 다룰수 있는 장점을 가지고 있다. 여러개의 프로세스가 하나의 메시지큐를 엑세스 할때, 각 메시지에 type 를 줌으로써 각 프로세스에게 필요로하는 메시지만을 가져가게 할수 있는 상당히 편리한 기능을 제공한다.

또한 구조체를 몽땅 넘길수 있고, 이는 데이타의 사용을 매우 편하게 만들어준다.

2 메시지큐의 생성, 사용, 제어

메시지큐를 생성하고, 이를 이용 및 조작하기 위해서 Unix 시스템은 다음과 같은 함수들을 제공한다. 앞으로의 설명은 아래의 함수들을 기준으로 이루어지게 될것이다.

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h> 
 
int msgget (key_t key, int msgflg) 
int msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) 
ssize_t msgrcv (int msqid, struct  msgbuf  *msgp,  size_t msgsz,  
                long msgtyp, int msgflg)  
 
Unix 커널은 메시지큐 정보를 유지하기 위해서 msqid_ds 라는 별도의 구조체를 유지한다. msqid_ds 구조체는 /usr/include/bits/msq.h 에 선언되어 있으며 대충 다음과 같은 구조를 가진다

이건 linux os 기준이며, Unix 에 따라 약간씩 다를수 있다
struct msqid_ds 
{ 
struct ipc_perm msg_perm; /* structure describing operation permission */ __time_t msg_stime; /* time of last msgsnd command */ unsigned long int __unused1; __time_t msg_rtime; /* time of last msgrcv command */ unsigned long int __unused2; __time_t msg_ctime; /* time of last change */ unsigned long int __unused3; unsigned long int __msg_cbytes; /* current number of bytes on queue */ msgqnum_t msg_qnum; /* number of messages currently on queue */ msglen_t msg_qbytes; /* max number of bytes allowed on queue */ __pid_t msg_lspid; /* pid of last msgsnd() */ __pid_t msg_lrpid; /* pid of last msgrcv() */ unsigned long int __unused4; unsigned long int __unused5; };
최초 msgget 를 이용해서 커널에 메시지큐를 요청하면, 커널은 해당 메시지큐를 위해 메모리를 할당하고, 메모리 관리와 그밖의 정보 관리를 위해 위의 구조체를 세팅하게 된다.

3 메시지큐 생성

메시지큐의 생성과 기존에 있던 메시지큐의 참조는 msgget(2) 를 이용해서 이루어진다. 첫번째 아규먼트인 key 는 kernel 에서 유일한 메시지큐를 만들고 참조하기 위해서 사용하는 식별번호이며, msgflg 는 메시지큐를 어떻게 생성하고 참조할지 행동양 식을 정해주기 위한 아규먼트이다. key 는 적당하게 유일한 int 형의 숫자를 정해주면 된다. msgflg 에는 IPC_CREAT와 IPC_EXCL등의 시작동작을 정해줄수 있으며, 퍼미션을 지정해 줄수도 있다.
IPC_CREAT
메시지큐를 새로 생성하기 위해서 사용한다. 만약 기존에 key 로 생선된 메시지큐가 있다면 해당 메시지큐의 식별자를 되돌려준다.
IPC_EXCL
IPC_CREAT 와 함께 쓰이며, IPC_EXCL이 지정되어 있을경우 이미 key 로 존재하는 메시지큐가 있다면, -1 을 리턴하고 errno 를 세팅한다.

msgget 는 성공할경우 메시지큐에 접근할수 있는 int 형의 메시지큐 식별자를 되돌려주며, 이후로는 이 메시지큐 식별자를 통해서 필요한 작업을 하게 된다.

4 메시지큐에 데이타 쓰기

메시지를 보내기 위해서는 msgsnd(2) 를 사용한다. 첫번째 아규먼트는 msgget 를 통해서 얻어온 메시지큐 식별자이며, 2번째 아규먼트는 메시지큐에 넘기고자하는 구조체, 3번째 아규먼트는 2번째 아규먼트인 구조체의 크기, 마지막 아규먼트는 메시지전달 옵션으로 봉쇄할것인지 아니면 비봉쇄로 메시지를 결정하기 위해서 사용된다.

2번째 아규먼트가 메시지큐로 전달할 메시지라고 했는데, 이것은 구조체로 전달 되며, 다음과 같은 모습을 가지게 된다.
struct msgbuf 
{ 
    long mtype; 
    char mtext[255]; 
} 
 
위의 모습은 메시지 구조체의 매우 전형적인 모습으로 사실멤버변수는 필요에 따라서 얼마든지 변경될수 있다. 다만 long mtype 만이 필수요소이다.

mtype 는 메시지의 타입으로 반드시 0보다 더큰 정수이여야 한다. 우리는 이 mtype 를 각각 다르게 줌으로써, 특정 프로세스에서 특정 메시지를 참조할수 있도록 만들수 있다. 예를 들어 A 라는 프로세스가 A 라는 메시 타입을 참조해야 하고 B 는 B 로 참조하도록 만들어야 한다면, msgbuf 를 만들때, mtype 에 A 은 1 B 은 2 이런식으로 메시지 타입을 정의 하고 A 는 mtype 가 1인것을 B는 mtype 이 2인것을 가지고 가도록 만들면 된다.

Upload new Attachment "queue.png"

위의 그림에서 처럼 mtype 을 이용해서 자신이 원하는 메시지에만 선택 적으로 접근이 가능하다. 이특성을 잘 이용하면 매우 유용하게 사용할수 있을것이다.

msgsz 은 구조체의 크기이니 그냥 넘어가고, msgflg 에 대해서 설명하겠다. msgflg 에는 IPC_NOWAIT를 설정할수 있으며 이 값을 이용해서 봉쇄형으로 할것인지 비봉쇄형으로 할것인지 결정할수 있다. IPC_NOWAIT를 설정하면, 메시지가 성공적으로 보내지게 될때까지 해당영역에서 봉쇄(block)되며, 설정하지 않을경우 에는 바로 return 하게 된다.

5 메시지큐의 데이타 가져오기

데이타는 msgrcv(2) 함수를 이용해서 가져올수 있다. 1번째 아규먼트는 메시지큐 식별자이며, 2번째가 가져올 데이타가 저장될 구조체, 3번째는 구조체의 크기, 4번째는 가져올 메시지 타입, 5번째는 세부 조종 옵션이다.

다른것들은 굳이 설명할 필요가 없는 간단한 것들이고, 다만 4번째 메시지 타입인 msgtyp에 대해서 상세히 설명하고, msgflg 를 간단히 설명하는 정도로 넘어가도록 하겠다. 우리는 메시지를 보낼 구조체를 만들때 mtype 라는것을 정의 해서, 메시지를 분류해서 접근할수 있도록 한다는것을 알고 있다. 메시지를 가져올때는 바로 msgtyp 를 통해서 자기가 원하는 msgtyp 의 메시지 구조체에 접근할수 있게 된다.
msgtyp == 0
메시지 큐의 첫번째 데이타를 돌려준다.
msgtyp > 0
메시지의 mtype 가 msgtyp 와 같은 첫번째 데이타를 돌려준다.
msgtyp < 0
메시지의 mtype 이 msgtyp 의 절대값보다 작거나 같은 첫번째 데이타를 돌려준다.

msgflg 는 msgrcv 의 메시지 가져오는 형태를 봉쇄로 할것인지 비 봉쇄로 할것인지 지정하기 위해서 사용한다. IPC_NOWAIT 를 설정할경우 가져올 메시지가 없더라도 해당 영역에서 봉쇄되지 않고 바로 error 코드를 넘겨주고 리턴한다.


6 예제를 통해 알아본 메시지큐

여기에는 총 2개의 예제프로그램이 만들어진다. 하나는 메시지큐 생산자로써, 메시지큐를 생성하고 메시지를 만들어서 메시지큐에 보내는(msgsnd) 일을 하고 다른 하나는 소비자로써 메시지큐에 있는 데이타를 받아오는 일을 한다. 다음은 메시지큐 생산자 이다.
#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <sys/stat.h>  
 
struct msgbuf 
{ 
    long msgtype; 
    char mtext[256]; 
    char myname[16]; 
    int  seq; 
}; 
 
int main() 
{ 
    key_t key_id; 
    int i; 
    struct msgbuf mybuf, rcvbuf; 
 
    key_id = msgget((key_t)1234, IPC_CREAT|0666); 
    if (key_id == -1) 
    { 
        perror("msgget error : "); 
        exit(0); 
    } 
 
    printf("Key is %d\n", key_id); 
 
    memset(mybuf.mtext, 0x00, 256);  
    memset(mybuf.myname, 0x00, 16);  
    memcpy(mybuf.mtext, "hello world 4", 13); 
    memcpy(mybuf.myname, "yundream", 8); 
    mybuf.seq = 0; 
    i = 0; 
 
    while(1) 
    { 
        // 짝수일경우 메시지 타입이 4 
        // 홀수일경우에는 메시지 타입이 3 
        if (i % 2 == 0) 
            mybuf.msgtype = 4; 
        else  
            mybuf.msgtype = 3; 
        mybuf.seq = i; 
 
        // 메시지를 전송한다.  
        if (msgsnd( key_id, (void *)&mybuf, sizeof(struct msgbuf), IPC_NOWAIT) == -1) 
        { 
            perror("msgsnd error : "); 
            exit(0); 
        }  
        printf("send %d\n", i); 
        i++; 
        sleep(1); 
    } 
 
    printf("%d \n", rcvbuf.msgtype); 
    printf("%s \n", rcvbuf.mtext); 
    printf("%s \n", rcvbuf.myname); 
    exit(0); 
} 
 
프로그램은 간단하다. mybuf 란 구조체를 만들어서 메시지를 전송하는데, 이때 메시지 타입을 i % 2 가 0일경우 4로 그렇지 않을경우 3으로 해서 전송을 하도록 만들었다.

#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/msg.h>  
#include <sys/stat.h>  
struct msgbuf 
{ 
    long msgtype; 
    char mtext[256]; 
    char myname[16]; 
    int  seq; 
}; 
 
int main(int argc, char **argv) 
{ 
    key_t key_id; 
    struct msgbuf mybuf; 
    int msgtype; 
 
    // 아규먼트가 있을경우 msgtype 가 3인 메시지를 받아오고(홀수)  
    // 아규먼트가 없을경우 msgtype 가 4인 메시지를 받아온다(짝수)   
    if (argc == 2) 
        msgtype = 3; 
    else  
        msgtype = 4; 
 
    key_id = msgget(1234, IPC_CREAT|0666); 
    if (key_id < 0) 
    { 
        perror("msgget error : "); 
        exit(0); 
    } 
    while(1) 
    { 
        if (msgrcv( key_id, (void *)&mybuf, sizeof(struct msgbuf), msgtype, 0) == -1) 
        { 
            perror("msgrcv error : "); 
            exit(0);     
        } 
        printf("%d\n", mybuf.seq); 
    } 
    exit(0); 
} 
 
이 예제는 더 간단하다. 아규먼트가 있으면 메시지타입이 3인 메시지를 아규먼트가 없으면 메시지 타입이 4인 메시지를 가져오도록 한다.

프로그램을 컴파일후 테스트를 해보면 ./msgrcv 1을 (아규먼트를 주고 실행) 실행시키면 msgtype 가 4인 메시지를 받아오고 그렇지 않을경우 msgtype 가 3인 메시지를 받아옴을 알수 있을것이다. ./msgsnd, ./msgrcv, ./msgrcv 1 을 동시에 띄워서 테스트하면 된다.

7 메시지큐의 제어

msgctl(2)함수를 이용한다. 첫번째 아규먼트인 msqid 는 메시지 식별자이며, 2번째 아규먼트인 cmd 는 해당 작동명령, 그리고 마지막 아규먼트는 msqid_ds 구조체 이다. 우리는 cmd 를 통해서 해당 메시지식별자가 가르키는 메시지큐를 제어할수 있다. cmd 에는 아래와 같은 종류의 명령을 사용할수 있다.

IPC_STAT
메시지큐의 정보를 원할때 사용한다. 해당 메시지큐의 정보는 3번째 아규먼트인 msqid_ds 구조체를 통해 넘어오게 된다.

IPC_SET
msqid_ds 구조체 정보를 변경하고자 할때 사용한다. 주로 퍼미션 정보를 바꾸기 위해서 사용한다.
IPCRMID
현재 메시지큐를 제거한다.

8 정리


이상 메시지큐에 대해서 간단히 알아보았다. 지금까지 설명에서 처럼 메시지큐는 내부 프로세스간 통신을 위한 상당히 유연한 방법을 제공하고 있음을 알수 있다. 반면 단점이 있는데, 제어하기가 상당히 까다롭다는 점이다.

우선 메시지큐에 들어갈수 있는 데이타의 수가 고정되어 있는데, 메시지큐가 어떤 이유로 꽉찼을 경우 이를 알수 있는 방법이 애매하다. 위의 예제에서 ./msgrcv 와 ./msgrcv 1 이 메시지를 계속적으로 소비하도록 되어 있는데, 만약 둘중 하나가 이상작동을 해서 메시지를 받아오지 못할경우 결국 메시지큐가 꽉 차버리게 되고, 더이상 정상적인 작동을 못하게 될것이다. 또한 커널의 영향을 많이 받으며, 잘못된 메시지큐의 사용은 전체 시스템에 영향을 미칠수도 있게 만든다. 이는 전체 시스템에서 사용할수 있는 메시지큐의 수와 크기에 제한이 있기 때문으로, 메시지큐를 사용하기 위해서는 조심해서 사용해야될 필요성이 있다.

또한 커널은 몇개의 프로세스가 현재 메시지큐를 참조하는지를 알려주는 참조계수를 제공하지 않는다. 그러므로 프로세스에 어떤 문제가 생겼을때, 해당 프로세스에 정확하게 어떤 문제가 발생했는지 알아내는게 상당히 까다롭다.

그러므로 메시지큐를 짧은 시간에 다량의 정보를 전달하기 위한 목적으로 사용하는 데에는 적당치 않다. 그리 많지 않은 정보를 프로세스간 교환하기 위한 용도로 사용하기에 적당한 IPC 설비이다.

9 참고문서



출처 : 조인시 위키

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Posted by 소리나는연탄.

Leave your greetings here.

  
  
  
  
  
  
  
  
 
2008년 1월 5, 12일,

각종 언론과, 신문지상에서 접한 보도보다는, 현지 실정을 좀 더 가까이서 느껴봐야겠다는 생각에 무작정 태안을 찾았다. 딴엔 현지의 모습을 자세히 남겨 내 주변사람에게도 알려주고 싶어 카메라에 켐코더까지 준비해갔지만... 태안...그곳에 첫발을 내딪자마자 그런 생각을 접어야했다. 한겨울의 매서운 바다바람은 둘째로 하더라도, 사방에서 불어오는 매케한 기름냄새로 머리가 아플정도였다.


두려움...분노...연민...

그리고....

희망
...


발 딛고 있는 백사장, 10센티만 파도 쌔까만 기름과 타르층이 나왔고, 저 바다 밑속엔 도대체 얼마만큼 더 있는지 오전 내내 기름과 타르덩어리를 제거 했던 백사장과 바위, 자갈들은, 밀물이 오고 다시 바다가 밀려가는 썰물때가 되자, 언제그랬냐는듯이 다시 기름과 타르덩어리들로 새까맣게 덮어버렸다... 정말 할말이 없었다...
10년이 넘게 걸릴지도 모른다는 신지문지상의 문구가 이런 의미였구나라는걸 오감으로 느겼던 순간이였다.


이유가 어찌되었던 자연파괴의 최대주범인 인간을 심판하는 자연의 무서움이란 하찮은 인간들이 감당하기엔 너무나 엄청난것이다. 어쩌다 이지경까지 되었단 말인가? 망연자실, 할말이 없다는 표현이 바로 이런 광경두고 한것일게다. 하지만 이 넓은 해변가 모든 백사장, 바위, 자갈, 돌들의 기름를 묵묵히 하나하나 제거 하고 닦고 있는 봉사자들, 썰물때 다시 쌔맣게 기름과 타르로 덮여버리는 해변이지만, 또다시 헝겊과 천을 들고 해변으로 가는 봉사자들을 보면서, 어찌보면 무의미할것 같은 저들의 몸짓에 가슴속깊이 뜨거운 감정을 느낄수 있었다...


'우리나라 정말 대단하다.'


이런 모습이 비록 남들이 비하하는 '냄비근성'이라 할지라도, 정말 대단하다라는 말외엔 다른 수식어를 붙일 수 가 없었다. 인간이 사악하긴 하지만 저들과 같은 사람들이 있기에 아직 우리 미래는 오늘보다 더 밝을꺼라 믿어 의심지 않는다. 동시대에 살면서, 남녀노소, 직업과 종교, 나이를 떠나 같은 옷, 같은 신발, 같은 밥을 먹으며, 같은 생각을 가지고, 어려운 시기를 함께 했던 모든 자원봉사분들게 진심어린 존경을 표합니다.


사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지
 
사용자 삽입 이미지

사용자 삽입 이미지


크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기
Posted by 소리나는연탄.

Leave your greetings here.

  
  
  
  
  
  
  
  
 
« Previous : 1 : ... 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : ... 33 : Next »