수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1693903
  • Today | 254
  • Yesterday | 588

3 Articles, Search for '쓰레드'

  1. 2007/05/17 시간 중심의 코드 성능 향상을 위한 팁
  2. 2007/05/15 Thread (쓰레드) 란 ? (4)
  3. 2007/05/11 쓰레드와 시그널
Programming/MFC2007/05/17 17:38

시간 중심의 코드 성능 향상을 위한 팁

Visual C++ 개념: C/C++ 프로그램 빌드

시간 중심의 코드 성능 향상을 위한 팁
빠른 코드를 작성하려면 해당 응용 프로그램의 모든 측면을 이해하고 시스템과 상호 작용하는 방법을 이해해야 합니다. 이 항목에서는 시간 중심의 코드 부분 성능을 향상시킬 수 있는 코딩 기법을 설명합니다.

요컨대, 시간 중심의 코드 성능을 향상시키려면 다음 사항을 알고 있어야 합니다.

프로그램에서 속도가 빨라야 하는 부분
코드의 크기와 속도
새로운 기능 사용에 따른 비용
작업 수행에 필요한 최소 작업
코드의 성능에 대한 정보는 성능 모니터(perfmon.exe)를 사용하여 얻을 수 있습니다.

캐시 적종 및 페이지 폴트
정렬 및 검색
MFC 및 클래스 라이브러리
공유 라이브러리
힙
스레드
작은 작업 집합
캐시 누락 및 페이지 폴트

프로그램 명령어 및 데이터를 찾아 보조 저장 장치로 이동하는 페이지 폴트뿐만 아니라 내부 및 외부 캐시에 대한 누락된 캐시 적중은 프로그램 성능을 저하시킵니다.

CPU 캐시 적중은 10–20 클럭 주기가 소요될 수 있습니다. 외장 캐시 적중은 20–40 클럭 주기가 소요될 수 있습니다. 프로세서가 초 당 5억개의 명령어를 처리하고 페이지 폴트 1회 당 2밀리초의 시간이 걸린다고 가정할 때 페이지 폴트는 100만 클럭 주기가 소요될 수 있습니다. 따라서 누락된 캐시 적중 및 페이지 폴트 횟수를 줄이는 코드를 작성하면 프로그램 실행 성능이 향상됩니다.

프로그램의 속도가 느린 이유 중 하나는 필요 이상으로 페이지 폴트가 많거나 캐시가 누락되기 때문입니다. 이러한 문제를 방지하려면 참조 집약성이 좋은 데이터 구조를 사용하는 것이 중요합니다. 참조 집약성이란 관련된 항목을 함께 두어 참조하기 쉽도록 하는 것을 의미합니다. 보기 좋은 데이터 구조라도 참조 집약성이 미약하면 속도가 느릴 수 있고 그 반대인 경우도 있습니다. 두 가지 예를 들겠습니다.

항목을 검색하거나 목록의 끝까지 이동할 때 건너 뛴 각 연결마다 캐시가 누락되거나 페이지 폴트가 발생할 수 있기 때문에 동적으로 할당된 연결 리스트는 프로그램 성능을 저하시킬 수 있습니다. 간단한 배열을 기초로 목록을 구현하면 캐싱은 더 좋아지고 페이지 폴트는 줄어들기 때문에 실제로 속도는 더 빨라질 수 있습니다. 배열의 크기가 커지기는 더 어려울 것이라는 사실을 감안하더라도 속도는 여전히 더 빠를 것입니다.
동적으로 할당된 연결 리스트를 사용하는 해시 테이블은 성능을 저하시킬 수 있습니다. 확장되는 경우 동적으로 할당된 연결 리스트를 사용하여 내용을 저장하는 해시 테이블의 성능은 그보다 상당히 더 떨어질 것입니다. 실제로 최종 분석에서는 상황에 따라 배열을 통한 단순한 선행 검색이 실제로 더 빠를 수 있습니다. "폐쇄형 해시"라는 배열 기반 해시 테이블은 종종 간과되긴 하지만, 성능이 뛰어난 구현 방법입니다.
정렬 및 검색
정렬은 일반적인 많은 작업에 비해 시간이 많이 소모됩니다. 불필요한 속도 저하를 방지하는 가장 좋은 방법은, 작업을 빨리 수행해야 하는 시간에는 정렬을 수행하지 않는 것입니다. 다음과 같은 방법을 사용할 수 있습니다.

작업을 빨리 수행해야 하는 시간이 지난 후에 정렬을 수행합니다.
작업을 빨리 수행해야 하는 시간 이전에 미리 데이터를 정렬합니다.
반드시 정렬해야 하는 데이터 부분만 정렬합니다.
경우에 따라서는 목록을 정렬된 순서로 빌드할 수 있습니다. 정렬된 순서로 데이터를 삽입해야 할 경우 참조 집약성이 떨어지는 더 복잡한 데이터 구조를 사용하게 되면 캐시 누락과 페이지 폴트가 발생할 수 있으므로 주의해야 합니다. 모든 경우에 적용할 수 있는 방법은 없습니다. 여러 방법을 사용해 보고 차이점을 평가해 보십시오.

다음은 정렬에 관한 몇 가지 일반적인 팁입니다.

스톡 정렬을 사용하여 버그를 최소화합니다.
정렬의 복잡성을 줄이기 위한 사전 작업을 하면 도움이 됩니다. 데이터를 한 번 전달하여 비교를 단순화하고 정렬을 O(n log n)에서 O(n)으로 줄이면 결과가 확실하게 미리 나타납니다.
실행하려고 하는 데이터와 정렬 알고리즘의 참조 집약성을 고려합니다.
검색은 정렬보다 사용할 수 있는 방법이 적습니다. 검색에서 시간이 중요한 경우에는 이진 검색이나 해시 테이블 조회가 가장 좋은 방법이지만 정렬의 경우와 마찬가지로 집약성을 염두에 두어야 합니다. 작은 배열을 통한 선형 검색은 페이지 폴트나 캐시 누락을 초래하는 포인터가 많은 데이터 구조를 통한 이진 검색보다 더 빠를 수 있습니다.

MFC 및 클래스 라이브러리
MFC(Microsoft Foundation Classes)를 사용하면 코드를 작성하는 일이 매우 간단해질 수 있습니다. 시간 중심 코드를 작성할 때는 일부 클래스에 내재하는 오버헤드를 주의해야 합니다. 시간 중심 코드에서 사용하는 MFC 코드를 검토하여 성능 요구 사항에 맞는지 확인하십시오. 다음은 반드시 알고 있어야 하는 MFC 클래스 및 함수 목록입니다.

CString MFC는 C 런타임 라이브러리를 호출하여 CString에 메모리를 동적으로 할당합니다. 일반적으로 Cstring은 동적으로 할당된 다른 문자열만큼 효율적이며, 동적으로 할당된 모든 문자열과 마찬가지로 동적 할당 및 해제에 따르는 오버헤드를 지닙니다. 스택에서의 간단한 char 배열을 사용하면 같은 작업을 더 빨리 수행할 수 있습니다. 상수 문자열을 저장하려면 Cstring을 사용하지 말고 const char *를 대신 사용합니다. CString 개체를 사용하여 수행하는 모든 작업에는 약간의 오버헤드가 따릅니다. 런타임 라이브러리인 문자열 함수를 사용하는 것이 더 빠를 수 있습니다.
CArray CArray는 일반 배열과는 달리 융통성을 제공하지만 프로그램에 융통성이 필요하지 않을 수도 있습니다. 배열의 구체적인 한계를 알면 대신 전역 고정 배열을 사용할 수 있습니다. Carray를 사용하는 경우에는 CArray::SetSize를 사용하여 크기를 설정하고, 재할당이 필요할 경우 Carray를 몇 개 요소만큼씩 증가시킬지를 지정하십시오. 이 값을 지정하지 않고 요소를 추가하면 배열이 자주 재할당되고 복사될 수 있는데, 이는 비효율적이며 메모리가 단편화될 수 있습니다. 또한 항목을 배열에 삽입하면 Carray는 다음 항목을 메모리로 이동시켜 배열의 크기가 커질 수 있습니다. 이로 인해 캐시 누락과 페이지 폴트가 발생할 수 있습니다. MFC에서 사용하는 코드를 검토하면 시나리오와 관려된 더 구체적인 코드를 작성하여 성능을 향상시킬 수 있습니다. 예를 들어, Carray는 템플릿이므로 특정 형식에 Carray 특수화를 제공할 수 있습니다.
CList CList는 이중 연결 리스트이므로 리스트의 맨 위, 맨 아래 및 알려진 위치(POSITION)에서 요소를 삽입하는 작업의 속도는 매우 빠릅니다. 요소를 값 또는 인덱스로 조회하려면 순차 검색이 필요하지만 리스트가 길면 오래 걸릴 수 있습니다. 코드에 이중 연결 리스트가 필요하지 않은 경우에는 Clist 사용을 다시 고려할 수 있습니다. 단일 연결 리스트를 사용하면 모든 작업에 대한 추가 포인터와 해당 포인터에 대한 메모리를 업데이트하는 오버헤드가 줄어듭니다. 추가로 사용되는 메모리 양은 얼마 안되지만 캐시 누락이나 페이지 폴트의 또 다른 원인이 됩니다.
IsKindOf 이 함수는 많은 호출을 생성하고 서로 다른 데이터 영역의 많은 메모리에 액세스할 수 있으므로 참조 집약성이 떨어지게 됩니다. 디버그 빌드(예: ASSERT 호출)에는 유용하지만 릴리스 빌드에서는 사용하지 않는 것이 좋습니다.
PreTranslateMessage 창의 특정 트리에 여러 키보드 액셀러레이터 키가 필요하거나 메시지 펌프에 메시지 처리를 삽입해야 할 때 PreTranslateMessage를 사용합니다. PreTranslateMessage는 MFC 디스패치 메시지를 변경합니다. PreTranslateMessage를 재정의하는 경우에는 필요한 수준에서만 재정의하십시오. 예를 들어, 특정 뷰의 하위 뷰로 전달되는 메시지에만 관심이 있다면 CMainFrame::PreTranslateMessage를 재정의할 필요가 없습니다. 대신 뷰 클래스의 PreTranslateMessage를 재정의하십시오.
창으로 보낸 메시지를 처리하려면 PreTranslateMessage를 사용하여 정상적인 디스패치 경로를 우회하지 마십시오. 정상적인 디스패치 경로를 우회하려면 창 프로시저와 MFC 메시지 맵을 사용하십시오.

OnIdle WM_KEYDOWN과 WM_KEYUP 이벤트 사이처럼 예상치 않은 시간에 유휴 이벤트가 발생할 수 있습니다. 코드를 트리거할 때는 타이머를 사용하는 것이 더 효율적인 방법일 수 있습니다. 거짓 메시지를 작성하거나 OnIdle 재정의에서 항상 TRUE를 반환하여 OnIdle이 강제로 반복 호출되지 않도록 하십시오. 이렇게 하면 스레드가 대기할 수 없게 됩니다. 이 경우에도 타이머나 별도의 스레드를 사용하는 것이 더 효율적일 수 있습니다.
공유 라이브러리
코드를 다시 사용하는 것이 바람직합니다. 그러나 다른 사람이 작성한 코드를 사용하려는 경우, 성능이 중요한 작업에 어떤 영향을 미치는지 정확히 알아야 합니다. 가장 좋은 방법은 소스 코드를 단계별로 실행하거나 PView 또는 성능 모니터 등의 도구를 사용하여 측정하는 것입니다.

힙
여러 개의 힙을 사용할 때는 신중해야 합니다. HeapCreate 및 HeapAlloc으로 만들어진 힙을 사용하여 관련된 할당 집합들을 관리한 다음 삭제할 수 있습니다. 너무 많은 메모리를 커밋하지 않도록 하십시오. 여러 힙을 사용하는 경우 처음에 커밋되는 메모리 양에 특히 주의하십시오.

여러 힙을 사용하는 대신 코드와 기본 힙 사이의 인터페이스에 대해 도우미 함수를 사용할 수 있습니다. 도우미 함수를 사용하면 응용 프로그램의 성능을 향상시킬 수 있는 사용자 지정 할당 전략을 쉽게 작성할 수 있습니다. 예를 들어, 작은 할당을 자주 수행하는 경우 기본 힙의 한 부분으로 할당을 지역화할 수 있습니다. 큰 블록의 메모리를 할당한 다음 도우미 함수를 사용하여 그 블록에서 다시 할당할 수 있습니다. 이 방법을 사용하면 기본 힙에서 할당이 이루어지므로 사용되지 않은 메모리를 지니는 추가 힙이 없어집니다.

그러나, 기본 힙을 사용하면 참조 집약성이 떨어지는 경우도 있습니다. 프로세스 뷰어, Spy++ 또는 성능 모니터를 사용하여 힙 간에 이동하는 개체의 영향을 측정하십시오.

힙을 측정하면 힙에 대한 모든 할당을 설명할 수 있습니다. C 런타임 디버그 힙 루틴을 검사점으로 사용하고 힙을 덤프합니다. Microsoft Excel 등의 스프레드시트 프로그램으로 결과를 읽어 오고 피벗 테이블을 사용하여 결과를 볼 수 있습니다. 할당의 전체 수, 크기 및 분포를 기록하고 작업 집합 크기와 비교하십시오. 관련 크기의 개체 클러스터링도 검토하십시오.

성능 카운터를 사용하여 메모리 사용을 모니터링할 수도 있습니다.

스레드
백그라운드 작업의 경우 이벤트 유휴 상태를 효율적으로 처리하는 것이 스레드를 사용하는 것보다 더 빠를 수 있습니다. 단일 스레드 프로그램에서는 참조 집약성을 이해하기가 더 쉽습니다.

가장 좋은 방법은 차단한 운영 체제 알림이 백그라운드 작업의 루트에 있는 경우에만 스레드를 사용하는 것입니다. 이러한 경우 이벤트에 대한 주 스레드를 차단하는 것이 비실용적이기 때문에 스레드를 사용하는 것이 가장 좋은 해결 방법입니다.

또한 스레드를 사용할 때는 통신 문제도 있습니다. 메시지 목록을 사용하거나 공유 메모리를 할당하여 사용하여 스레드 사이의 통신 연결을 관리해야 합니다. 통신 연결을 관리하려면 일반적으로 경쟁 상태와 교착 상태 문제를 방지하기 위해 동기화가 필요합니다. 이러한 복잡성 때문에 버그와 성능 문제가 발생하기 쉽습니다.

자세한 내용은 유휴 루프 처리 및 다중 스레딩을 참조하십시오.

작은 작업 집합
작업 집합의 크기가 작아질수록 참조 집약성은 더 좋아지고, 페이지 폴트는 줄어들며, 캐시 적중은 더 높아집니다. 프로세스 작업 집합은 운영 체제에서 참조 집약성을 측정하기 위해 직접 제공하는 가장 가까운 메트릭입니다.

작업 집합의 상한 및 하한을 설정하려면 SetProcessWorkingSetSize를 사용합니다.
작업 집합의 상한 및 하한을 구하려면 GetProcessWorkingSetSize를 사용합니다.
작업 집합의 크기를 보려면 Spy++를 사용합니다.

출처 : http://msdn.microsoft.com/library/kor/d ··· code.asp
"MFC" 카테고리의 다른 글
  • 쓰레드 풀 (Thread Pooling) 작성 (1)2007/05/17
  • 시간 중심의 코드 성능 향상을 위한 팁 (0)2007/05/17
  • 상태바위에 ProgressBar 올리기 #2 (0)2007/05/17
  • 상태바위에 ProgressBar 올리기 #1 (0)2007/05/17
  • 다이얼로그상의 특정 컨트롤의 색상 변경 (0)2007/05/17
2007/05/17 17:38 2007/05/17 17:38
Posted by webdizen
Tags MFC, 검색, 공유 라이브러리, 쓰레드, 정렬, 캐시 누락, 캐시 적종, 코드 성능 향상, 페이지 폴트, 힙
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2983

Leave your greetings.

[로그인][오픈아이디란?]

Programming/MFC2007/05/15 09:24

Thread (쓰레드) 란 ?

Nov 19 2002 16:20 Written by www.anygate.com


1. 쓰레드란?

용어가 그렇게 중요하지 않을 수도 있다는 생각을 가끔한다.
쓰레드란 표현도 그러한 용어중에 하나이다.
쓰레드라는 용어의 개념을 인지하기 전에 우린 이미 쓰레드를 사용하고 있으니 말이다.
이 글을 보는 사람은 누구나 Hellow World! 라는 전혀 쓸모없어 보이는
(프로그래밍에 첫 발을 디디는 사람들에겐 전설적인 프로그램이지만 지금은 냉정해질 필요가 있다.),
그러나 실행 가능한 프로그램을 작성해 보았을 것이다. 거기에도 쓰레드는 존재한다.
컴파일된 프로그램은 명령코드로 변환되어 디스크에 저장된다.
그리고 프로그램이 실행되면 운영체제에 의해 메모리에 올려지고 각각의 명령코드는 순서대로 실행된다.
이 정도의 지식만 있다면 현실 세계의 '실타래'를 전산용어인
쓰레드의 의미로 유추하는 일이 그리 어렵진 않을 것이다.
쓰레드란 바로 코드의 실행 흐름을 뜻하는 것이다.


2. 프로세스와 쓰레드

프로세스란 실행중인 프로그램을 의미한다.
좀 더 근사하게 말하면 실행중인 프로그램의 인스턴스(intance) 이다.
언뜻 프로세스와 쓰레드가 같은 개념으로 이해될 소지도 있지만 분명 차이는 있다.
초보자에게 가장 분명한 차이는 프로세스가 코드를 실행하지 않는다는 것이다.
앞서 프로그램이 실행되면 운영체제가 메모리에 실행코드를 올린다고 했는데
그 외에도 필요한 데이터와 운영체제가 그 프로그램을 위해 할당해 주는
시스템 자원(파일, 통신포트 같은)등도 함께 올려지며
이런 것들이 올려진 메모리의 주소영역을 갖고 있는것이 프로세스이다.
또한 결정적으로 쓰레드를 소유하는 것도 프로세스이다.
그래야 하나의 프로그램을 실행하는데 필요한 완벽한 준비가 될게 아닌가?
모든 것을 프로세스가 소유하므로 당연히 프로그램의 실행종료는
프로세스의 종료를 뜻하며 종료된 프로세스는 모든 자원을 운영체제에 되돌려 준다.

프로세스는 적어도 하나 이상의 쓰레드를 갖는다.
'적어도' 라는 말은 '반드시'라는 말과 같다.
반드시 필요한 하나의 쓰레드 (primary thread)를 메인 쓰레드 혹은 최우선 쓰레드라고도 하는데
용어야 뭐 대수겠는가? 어차피 응용 프로그램의 실행을 위한 기본적인 쓰레드를 말하는 것인데.

프로세스가 생성되면 메인 쓰레드는 프로세스가 할당한 메모리 영역에서 실행되며
프로세스에 할당된 시스템 리소스를 사용하게 된다.
쓰레드는 그 자체가 또 다른 쓰레드를 생성해 낼 수 있는데
결국 하나의 프로세스가 여러개의 쓰레드를 소유한 셈이며
이를 멀티 쓰레드(multi-thread)라고 말한다.
생성 가능한 쓰레드의 수는 몇 개일까?
프로세스가 할당받은 메모리의 크기가 허용하는 한 무한하다.


3. 윈도우즈와 멀티태스킹(multi-tasking)

윈도우즈는 멀티태스킹이 지원된다.
태스크(task)라는 말은 프로세스와 같은 개념으로 봐도 된다.
즉 여러개의 응용 프로그램이 동시에 실행되며 처리된다는 얘기이다.
주의할 점은 멀티태스킹이 단지 여러개의 프로그램을 실행만 시킨다는 뜻은 아니라는 것이다.
이것은 모니터로 윈도우즈를 지켜보고 있을때 쉽게 오해될 수 있다.
여러개가 실행되었지만 결국 사용하는 프로그램은 오로지 하나 아닌가?
사실 문서작성기에 열심히 타이핑하고 있는 사용자는 윈도우즈가
전적으로 문서작성기에만 신경을 곤두 세우고 있으리라 착각하기 쉽다.
그러나 윈도우즈는 비활성화되어 있는 다른 프로그램에도 똑같은 양의 관심을 가지고 있다.
공평한 배신자(?)인 셈인데 이는 윈도우즈 입장에서보면 배신이 아니고
여러개의 프로그램을 동시에 이용할 수 없는 사용자의 한계일 뿐이다.

두 개의 문서작성기에 동시에 입력할 수 있는가?
이것이 가능하다면 윈도우즈는 기꺼이 처리해 줄 것이다.

그럼 어떻게 윈도우즈가 여러개의 프로그램을 동시에 실행해 줄 수 있는가?
바로 시간을 쪼개 쓰는 것이다.
점잖게 '시분할'이라고 표현하는데 아주 짧은 시간동안에 윈도우즈는
다수의 프로그램 각각이 가진 실행코드를 돌아가며 조금씩 처리해 주는 방식이다.
그 시간은 굉장히 짧은 것이어서 사용자는 이를 눈치채지 못한다.
물론 실행된 프로그램이 많아진다면 이른바 과부하가 걸려 실행이 느려지기 시작하지만...

위에서 여러개의 프로그램이란 말을 여러개의 프로세스라는 말로 바꾸어 다시 설명한다면
윈도우즈는 (정확히는 윈도우즈의 커널) 모든 프로세스가 CPU를
공평하게 나누어 쓸 수 있도록 관리한다.
커널에 의해 각각의 프로세스는 굉장히 짧은 시간동안 CPU를 독차지하며
그동안 다른 프로세스는 순서가 올 때까지 대기하게 된다.
따라서 엄격히 말하면 현재 실행중이 아니거나 CPU를 사용하기 위해 기다리는 동안은
프로세스라고 할 수 없다. 어떤 책에는 프로세스가 기계의 현재 상태를 의미한다고 나와 있기도 하다.

참고로 윈도우즈는 이벤트 메시지 핸들 방식을 취한다.
즉 어떤 사건이 발생하면 메시지가 발생하고 사건이 발생된
윈도우(응용 프로그램)에 메시지가 보내져서 처리된다.
따라서 시분할이 적용되더라도 메시지를 가장 많이 받는 프로그램이
CPU를 상대적으로 많이 점유하는 형태가 된다.
그렇더라도 여전히 윈도우즈는 놀고있는 백수 프로그램에도
처리해야할 메시지가 있는가를 꼬박꼬박 돌아가며 확인한다.


4. 멀티 쓰레드와 쓰레드 함수

넓게 본다면 윈도우즈가 하나의 프로그램이고 윈도우즈에서 실행되는
여러개의 응용 프로그램들은 윈도우즈가 가진 다수의 쓰레드라고 볼 수 있다.
이 말은 사실이고 이것을 하나의 프로그램에 적용해 보면 쓰레드의 개념이 보다 확실해 진다.
대개 한 프로그램에서 동시에 여러가지 작업을 처리하는 경우는 드물지만
반드시 동시에 처리하지 않으면 안되는 작업이 있을 수 있다.
단일 쓰레드에선 동시 작업이 있을 수 없다.
하나의 코드가 실행되기 위해서는 그 전 코드의 실행이 끝나야만 하기 때문이다.
예를 들어 슈팅게임에서 총알을 발사했을때 프로그램된 일정량의 총알 궤적이 그려지는 작업이
끝나기 전에는 2번째 총알을 발사할 수 없게 된다면 얼마나 답답할 것인가?
반대로 총알을 그리는 작업이 쓰레드를 사용하여 메인 프로그램과는 상관없이
실행된다면 메인 프로그램은 따발로 총알을 갈겨댈 수 있을 것이다.(표현이 거칠군...)

자! 그럼 쓰레드는 어떻게 작성하는 것인가?

쓰레드는 일반 함수의 형태를 띤다.
그리고 그 형태는 정해져 있다.
다음이 쓰레드 함수의 원형인데 리턴형과 인자를 빼곤 당연히 함수명은 여러분 마음대로 정한다.



이 함수가 실행되면 쓰레드는 시작되며 함수실행이 끝나면 쓰레드도 끝난다.
이 함수도 값을 리턴하지만 프로그램에서 쓰레드 함수의 실행명령은
다음 명령의 실행에 아무런 영향을 미치지 않는다.
즉 쓰레드의 시작과 동시에 쓰레드가 종료되지 않았더라도
쓰레드 함수를 호출한 이후의 명령은 물 흐르듯이 순서대로 실행된다는 것이다.
메인 프로그램이 실행되는 동안 쓰레드는 배후에서 일을 하게 된다.
(그래야 동시작업의 의미가 있잖은가?)

쓰레드 함수의 리턴값은 실행의 성공여부를 알리는데 사용하며
보통 정상적으로 종료되었을때 '0'을, 아니면 '0'이 아닌 값을 리턴하게 된다.
(물론 프로그래머가 해줄 일이다.)

함수의 인자는 32bit 크기의 값이며 쓰레드 작업에 필요한 어떠한 형태의 정보(변수)든
이 인자를 통해 메인 프로그램으로부터 전달받을 수 있다.
이 인자의 사용에 대해서는 조금 후에 다시 언급하겠다.

이제 이 함수를 실행하는 일만 남았는데 이 함수의 직접호출은 배후작업을 지시하지 못한다.
쓰레드를 생성하기 위해선 MFC가 준비한 전역함수 AfxBeginThread(...)를 사용하게 되는데
다음이 이 함수의 원형이다. (2가지 버전이 있음)




두 버전의 쓰임새는 쓰레드의 종류에 따라 달라지는데 작업 쓰레드 (Worker thread)일 경우 전자를,
사용자 인터페이스 쓰레드 (User interface thread)일 경우엔 후자를 선택하게 된다.

쓰레드의 구분은 MFC를 사용한 프로그래밍에서 유효하며 win32 프로그래밍에선 쓰레드의 구분이 없다.
두 버전의 첫번째 인자를 보면 쉽게 구분이 갈 것이다.
여기서는 작업 쓰레드에 대해서만 다루겠다.

첫번째 인자는 위에서 만든 쓰레드 함수를 말하는데 단순히 함수명만 전달해 주면 된다.
두번째 인자는 쓰레드 함수의 인자에 사용되는 것과 동일한 32bit 값이다.
세번째 인자는 쓰레드의 우선순위이다. 보통 디폴트값을 그대로 사용하는데
이렇게 되면 쓰레드의 실행 순위는 다른 쓰레드와 동등해 진다.
작업내용에 따라 우선 순위를 특별하게 지정해야 한다면 라이브러리를 참조하기 바란다.
네번째 인자는 쓰레드에서 사용할 스택의 크기를 지정한다.
다섯번째 인자는 쓰레드 생성을 제어하는 플래그로 디폴트값처럼 '0'이 지정되면
쓰레드는 생성즉시 실행되며 CREATE_SUSPENDED를 지정하면
다른 쓰레드가 중지되기 전까지 실행을 지연시키게 된다.
마지막 인자는 보안속성을 나타내는 SECUTRITY_ATTRIBUTES 구조체를 가리키는데
보통 NULL을 사용한다.

두 버전 모두 생성된 쓰레드 객체의 포인터(CWinThread*)를 반환한다.
이 포인터를 사용하여 SuspendThread()나 ResumeThread()를 호출하면
쓰레드의 실행을 중지시킬 수도 있고 중지된 쓰레드를 다시 실행시킬 수도 있다.
CWinThread 클래스의 멤버들은 라이브러리를 참조하라.


5. 쓰레드 함수 사용예제

① 작업 쓰레드 함수의 작성



쓰레드 함수 내에서 맨 마지막 코드인 "return 0;"이 실행되면 쓰레드는 끝난다.
이 방법말고 쓰레드 내부에서 쓰레드를 종료하는 방법으로
AfxEndThread( UINT nExitCode )를 사용할 수도 있다.
만약 쓰레드 외부에서 쓰레드를 종료시키려면 API 함수인 TerminateThread(...)를 사용한다.
그러나 전역변수를 사용하여 쓰레드 내부에서 종료조건을 판단하는 루틴을 둔다면
쓰레드 내부에서 얼마든지 같은 효과를 볼 수 있다.
이 방법에 대해선 조금 후에 설명하겠다.

② 작업 쓰레드 함수의 실행



한가지 주의할 점은 쓰레드 함수가 C함수이므로 클래스의 멤버함수가 될 수 없다는 것이다.


6. 데이터의 전달

쓰레드 함수가 작업을 하기 위해 메인 프로그램의 데이터가 필요할 수 있다.
이 데이터는 윈도우 객체일 수도 있고 기타 구조체나 단순한 변수일 수도 있는데
그럴경우 쓰레드 함수의 LPVOID형 인자를 통해 전달해 주고
쓰레드 함수 내에서는 형변환을 사용하여 이를 취급할 수 있다.
그러나 전달해 주어야할 데이터가 많아진다면 어떻게 할 것인가?
가장 간단한 방법은 여러개의 변수를 묶은 구조체를 정의하고
그 구조체의 포인터를 전달하는 것이다.
또 다른 방법은 전역변수를 사용하는 것이다.
전역변수의 사용은 쓰레드 함수 외부, 즉 메인 프로그램에서 쓰레드를 제어하는데도 효과적이다.

예를들어 메인 프로그램에서 사용자의 입력을 받아 쓰레드에 해당 작업을 지시하는 방법을 보자.
메인 프로그램에서는 메뉴 또는 대화상자를 통해 사용자로부터
"작업1", "작업2", "작업3" 등의 명령을 처리하는 핸들러를 작성할 수 있다.
이때 그 명령처리 함수에서는 단지 전역변수에 작업의 종류만을 넣어주면
쓰레드에서 곧바로 실행할 수 있다.

다음은 쓰레드 함수에서의 처리방법이다.



이것은 아주 간단한 예에 불과하지만 효과적이다.
모든 작업 쓰레드는 모든 전역변수를 사용할 수 있기 때문이다.
"MFC" 카테고리의 다른 글
  • WaitForSingleObject() 에 의한 Thread 동기화 (0)2007/05/15
  • 응용 프로그램의 INI 파일 바꾸기 (0)2007/05/15
  • Thread (쓰레드) 란 ? (3)2007/05/15
  • Using User-Interface Threads (0)2007/04/29
  • Worker Threads (0)2007/04/29
2007/05/15 09:24 2007/05/15 09:24
Posted by webdizen
Tags Thread, 쓰레드
No Trackback 4 Comments

Trackback URL : http://www.webdizen.net/blog/trackback/2951

Leave your greetings.

  1. 김석경

    잘 보고 갑니다...개념 정리에 도움이 되었어요.

    2008/12/30 03:42 [ Permalink : Modify/Delete : Reply ]
    • webdizen

      도움이 되었다니, 기분이 좋아지네요.

      2009/01/12 22:29 [ Permalink : Modify/Delete ]
  2. ham

    잘보고 갑니다. 담아갈게요~

    2009/10/09 17:47 [ Permalink : Modify/Delete : Reply ]
  3. 장진혁

    학교 과제물중 쓰레드에 대하여 알아오라고 하였는데
    MFC까지 배우지 않아서 잘 모르겠지만 위쪽 설명만으로도 개념이 정리가 되네요...
    좋은 정보 감사합니다. (__)

    2010/03/17 11:41 [ Permalink : Modify/Delete : Reply ]
[로그인][오픈아이디란?]

Programming/UNIX/Linux C2007/05/11 10:15

쓰레드와 시그널

그렇잖아도 애매모호한 쓰레드에 헷갈리는 시그널을 사용하고자 하면 여러가지 애로사항이 꽃피게 된다. 각 쓰레드별로 시그널이 전달되거나 전달되지 않도록 설정할 수 있어야 하기 때문인데, 개념적으로는 간단하지만 막상 적용하려면 그 과정이 머리에 그려지지 않기 때문이다.


차례
1. 쓰레드에서의 시그널 사용
1.1. 시그널을 특정 쓰레드로 보내기
1.1.1. 간단 예제
1.2. 쓰레드간 시그널 전송
1.2.1. 다른 쓰레드로 시그널 전송
1.2.2. 시그널 받기
1.2.3. 예제
1.2.4. 시그널을 이용한 쓰레드 작동 제어
1.3. 운영체제별 차이점


1. 쓰레드에서의 시그널 사용
쓰레드에서의 시그널 사용은 시그널에 대한 기본적인 이해만 가지고 있다면 약간의 응용으로 충분히 해결할 수 있는 문제이긴 하지만 범 유닉스적으로 응용하고자 한다면(특히 리눅스가 포함된다면) 운영체제간 신경써줘야할 문제가 있다. 이번장에서는 쓰레드에서의 시그널을 이용하는 방법과 운영체제가 다름으로 인해 발생할 수 있는 문제들에 대해서 알아보도록 하겠다.


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

1.1. 시그널을 특정 쓰레드로 보내기
쓰레드에서 시그널은 서로 공유된다는걸 알고 있을 것이다. 문제는 공유된다는 점인데 만약 프로세스에 시그널을 보낼 경우 해당 프로세스에서 생성된 모든 쓰레드에 시그널이 전달이 되게 된다. 이것은 우리가 원하는게 아니다.

우리가 원하는 것은 특정 쓰레드에서만 시그널을 받도록 하는 것이다. 이러한 작업을 위해서 우리는 시그널 마스크를 사용한다. 시그널 마스크는 말그대로 특정 시그널에 대해서 마스크를 씌우는 것으로 해당 쓰레드에서 특정 시그널에 대해서 마스크를 씌우면 마스킹된 시그널은 해당 쓰레드로 전달되지 않는다. 이 시그널을 받기를 원하는 쓰레드에서는 이 시그널에 대한 마스크를 제거시킨다. 그러면 블럭되어 있는 시그널은 마스크가 제거된 쓰레드로 전달될 것이다. 일종의 필터기다.

사용자 삽입 이미지
그림 1. 시그널 마스크의 작동원리
 

위의 그림은 시그널 마스크의 작동원리를 보여준다. 메인 쓰레드에서는 SIGINT와 SIGUSR2에 대해서 시그널 마스크를 설치한다. 그리고 쓰레드 1에서는 SIGINT에 대한 마스크를 제거하고, 쓰레드 2에서는 SIGUSR2에 대한 마스크를 제거한다. 이렇게 되면 SIGINT가 메인 쓰레드에 도착했을 때 마스크 때문에 메인 쓰레드에는 도착하지 못하고 쓰레드 1로 전달될 것이다. SIGUSR2가 도착했을 경우 메인 쓰레드와 쓰레드 1에서는 마스크 때문에 전달되지 못하고 쓰레드 2로 시그널이 전달된다. 1.1.1절에서는 위의 작동원리 대로 구현된 예제 코드를 다루고 있다.

이러한 쓰레드별 시그널 마스킹을 위해서 pthread는 pthread_sigmask(3)라는 함수를 제공한다.

                       

이 함수는 현재 쓰레드에 시그널newmask와 how 를 이용해서 시그널 마스크를 만든다. how는 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK중 하나를 선택할 수 있다. SIG_BLOCK는 현재 설정된 시그널 마스크에 newmask를 추가하며 SIG_UNBLOCK는 현재 설정된 시그널 마스크에서 newmask를 제거하고 SIG_SETMASK는 newmask로 현재 시그널 마스크를 설정한다.


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

1.1.1. 간단 예제
그럼 pthread_mask(3)를 이용한 간다한 예제를 만들어 보도록 하겠다. 코드는 여러분이 시그널과 쓰레드에 관한 최소한의 지식을 가지고 있다는 가정하에 작성될 것이며, 설명은 주석으로 대신하도록 하겠다.

예제 : th_signal.c

                               

위 프로그램을 실행시킨뒤 kill명령으로 SIGINT와 SIGUSR2 시그널을 PID로 보내보면 해당 쓰레드로 시그널이 전달되고 시그널 핸들러가 실행되는걸 확인할 수 있을 것이다.

위의 그림은 시그널 마스크의 작동원리를 보여준다. 메인 쓰레드에서는 SIGINT와 SIGUSR2에 대해서 시그널 마스크를 설치한다. 그리고 쓰레드 1에서는 SIGINT에 대한 마스크를 제거하고, 쓰레드 2에서는 SIGUSR2에 대한 마스크를 제거한다. 이렇게 되면 SIGINT가 메인 쓰레드에 도착했을 때 마스크 때문에 메인 쓰레드에는 도착하지 못하고 쓰레드 1로 전달될 것이다. SIGUSR2가 도착했을 경우 메인 쓰레드와 쓰레드 1에서는 마스크 때문에 전달되지 못하고 쓰레드 2로 시그널이 전달된다. 1.1.1절에서는 위의 작동원리 대로 구현된 예제 코드를 다루고 있다.

이러한 쓰레드별 시그널 마스킹을 위해서 pthread는 pthread_sigmask(3)라는 함수를 제공한다.

                       

이 함수는 현재 쓰레드에 시그널newmask와 how 를 이용해서 시그널 마스크를 만든다. how는 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK중 하나를 선택할 수 있다. SIG_BLOCK는 현재 설정된 시그널 마스크에 newmask를 추가하며 SIG_UNBLOCK는 현재 설정된 시그널 마스크에서 newmask를 제거하고 SIG_SETMASK는 newmask로 현재 시그널 마스크를 설정한다.


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

1.1.1. 간단 예제
그럼 pthread_mask(3)를 이용한 간다한 예제를 만들어 보도록 하겠다. 코드는 여러분이 시그널과 쓰레드에 관한 최소한의 지식을 가지고 있다는 가정하에 작성될 것이며, 설명은 주석으로 대신하도록 하겠다.

예제 : th_signal.c

                               

위 프로그램을 실행시킨뒤 kill명령으로 SIGINT와 SIGUSR2 시그널을 PID로 보내보면 해당 쓰레드로 시그널이 전달되고 시그널 핸들러가 실행되는걸 확인할 수 있을 것이다.

위의 그림은 시그널 마스크의 작동원리를 보여준다. 메인 쓰레드에서는 SIGINT와 SIGUSR2에 대해서 시그널 마스크를 설치한다. 그리고 쓰레드 1에서는 SIGINT에 대한 마스크를 제거하고, 쓰레드 2에서는 SIGUSR2에 대한 마스크를 제거한다. 이렇게 되면 SIGINT가 메인 쓰레드에 도착했을 때 마스크 때문에 메인 쓰레드에는 도착하지 못하고 쓰레드 1로 전달될 것이다. SIGUSR2가 도착했을 경우 메인 쓰레드와 쓰레드 1에서는 마스크 때문에 전달되지 못하고 쓰레드 2로 시그널이 전달된다. 1.1.1절에서는 위의 작동원리 대로 구현된 예제 코드를 다루고 있다.

이러한 쓰레드별 시그널 마스킹을 위해서 pthread는 pthread_sigmask(3)라는 함수를 제공한다.

                       

이 함수는 현재 쓰레드에 시그널newmask와 how 를 이용해서 시그널 마스크를 만든다. how는 SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK중 하나를 선택할 수 있다. SIG_BLOCK는 현재 설정된 시그널 마스크에 newmask를 추가하며 SIG_UNBLOCK는 현재 설정된 시그널 마스크에서 newmask를 제거하고 SIG_SETMASK는 newmask로 현재 시그널 마스크를 설정한다.


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

1.1.1. 간단 예제
그럼 pthread_mask(3)를 이용한 간다한 예제를 만들어 보도록 하겠다. 코드는 여러분이 시그널과 쓰레드에 관한 최소한의 지식을 가지고 있다는 가정하에 작성될 것이며, 설명은 주석으로 대신하도록 하겠다.

예제 : th_signal.c

                               

위 프로그램을 실행시킨뒤 kill명령으로 SIGINT와 SIGUSR2 시그널을 PID로 보내보면 해당 쓰레드로 시그널이 전달되고 시그널 핸들러가 실행되는걸 확인할 수 있을 것이다.

1.2. 쓰레드간 시그널 전송
외부의 다른 프로세스에서 시그널을 발생시키는 것 외에도 같은 프로세스에서 작동하는 쓰레드간에 시그널을 전송해야 하는 경우도 생길 것이다.

이러한 쓰레드간 시그널 전송은 여러가지 목적으로 사용할 수 있다. 일정시간마다 특정 쓰레드에 시그널을 전송하므로써 쓰레드를 깨워서 코드를 실행시키게 한다거나 네트워크 애플리케이션에서 write, read에 타임아웃을 검사하는 용도로도 사용가능 하다.

네트워크 애플리케이션에서 스레드간 시그널 전달을 통해 타임아웃을 검사한다는 생각은 좀 생소할 수도 있을것 같다. 보통은 select나 alarm을 사용할 건데, 멀티 쓰레드 프로그램의 경우 alarm(2)의 사용은 사실상 어렵다고 볼 수 있다. 여러개의 쓰레드에서 alarm(2)을 사용할 경우 단지 하나의 alarm(마지막 alarm값)만이 등록되어서 사용할 수 있기 때문이다. 그렇다면 select를 사용해야 할 건데, select대신에 전용의 시그널을 발생하는 쓰레드를 이용해서 사용할 수 있다.

read(2)를 예로 들어서 설명해 보자 read(2)를 하기전에 특정 (전역)값을 0으로 세팅하고 read를 수행한후 1로 값을 변경하도록 한다. 그리고 타임아웃 체크를 위한 쓰레드에서는 타임아웃 시간 간격으로(sleep(2)를 이용하면 된다) 이 값을 검사한다. 만약 값이 0으로 세팅되어 있는걸 확인 했는데, 다음 시간이 돌아온 뒤에도 이 값이 0이라면 read영역에서 타임아웃이 발생했다고 판단 할 수 있을 것이다. 그러면 타임아웃이 발생한 쓰레드에 시그널을 전송하도록 한다. 쓰레드에 시그널이 전송하면 인터럽트가 발생하고 read에서 빠져나오게 된다.


                       

시그널 발생시 인터럽트가 전달되게 하려면 약간의 부가적인 작업이 필요한데, 이것은 소켓 타임아웃을 참고하기 바란다.



1.2.1. 다른 쓰레드로 시그널 전송
이러한 쓰레드간 시그널 전송을 위해서 pthread_kill(3)이라는 함수가 제공된다.
                               

첫번째 인자thread는 시그널을 전달받을 쓰레드의 식별자이고 signo는 전달하고자 하는 시그널 번호이다. 보내는 쪽은 pthread_kill(3)을 이용해서 비교적 간단하게 구현이 가능하다.


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

1.2.2. 시그널 받기
시그널을 받는 쓰레드의 경우 동기와 비동기 두가지 방식을 통해서 받을 수 있다. 동기 방식으로 받을 경우는 sigwait(3)함수를 이용해서 시그널이 전달될 때까지 블럭되면서 기다린다.

                               

이 함수는 시그널 셋set에 설정된 시그널중 하나가 전달될 때까지 호출된 영역에서 대기한다. 시그널을 받았다면 리턴되고 전달 받은 시그널 번호는 sig를 통해서 넘어온다. 시그널을 기다린다는 특징을 이용해서 쓰레드간 동기화를 위한 목적으로도 유용하게 사용할 수 있을 것이다.

두번째는 비동기적인 방식으로 코드 실행중에 시그널이 전달되면 인터럽트가 걸리고 시그널 핸들러가 수행되는 방식이다. 일반적인 시그널 사용방식과 동일하다.

1.2.3. 예제
sigwait(3)를 통해서 동기적으로 기다리는 것은 구현이 간단하므로 따로 다루지 않고 시그널 핸들러를 등록해서 비동기적으로 시그널을 기다리는 코드를 구현해 보도록 하겠다. 1.1.1절의 코드를 약간 수정했다.

예제 : thtoth_sig.c

                               

위의 코드의 경우 시그널을 받을 쓰레드를 명시해줄 수 있으므로 시그널 마스크등을 설치할 필요가 없다. SIGINT가 원하는 쓰레드로 정확하게 전달되는걸 확인할 수 있을 것이다.

1.2.4. 시그널을 이용한 쓰레드 작동 제어
쓰레드 프로그래밍을 하다보면 비동기 적으로 특정 쓰레드를 중단 시켜야 되는 경우가 발생한다. 물론 임의의 시점에서 중단된 쓰레드를 다시 작동하도록 만들어 주어야 할것이다.

다른 우회적인 몇가지 구현 방법이 있겠지만 비동기적인 처리를 위해서는 역시 시그널만한게 없는 것 같다.
                               


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

1.3. 운영체제별 차이점
쓰레드의 작동방식은 운영체제별로 많은 차이를 보여줄 수 있으며, 차이점에 유의해서 프로그램을 작성해야 한다. 여기에서는 솔라리스와 리눅스를 비교해서 설명하도록 하겠다.

지금까지의 쓰레드와 시그널에 대해서 다루었던 내용은 솔라리스와 같이 하나의 프로세스에서 다중의 쓰레드를 관리하는 경우를 기준으로 했다. 그러나 리눅스의 경우 clone(2)를 통한 다중 프로세스형태로 쓰레드가 생성된다. 때문에 ps를 이용해서 확인할 경우 다중 쓰레드 프로세스임에도 불구하고 각각의 PID를 가지는 프로세스로 쓰레드가 생성되는걸 확인 할 수 있다.

이런 특징 때문에 리눅스 시스템에서 외부 프로세스에서 시그널을 특정 쓰레드로 보낼 경우에는 메인 쓰레드가 아닌 해당 쓰레드의 PID를 명시해 주어야 한다.




출처 : http://joinc.co.kr/modules.php?name=new ··· 3Dnested
"UNIX/Linux C" 카테고리의 다른 글
  • pthread API 레퍼런스 (3)2007/05/14
  • 안전한 프로그래밍 (0)2007/05/11
  • 쓰레드와 시그널 (0)2007/05/11
  • Zlib를 이용한 압축 프로그래밍 (0)2007/05/11
  • proc파일시스템 프로그래밍 (0)2007/05/11
2007/05/11 10:15 2007/05/11 10:15
Posted by webdizen
Tags Signal, Thread, 시그널, 쓰레드
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2925

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 이터레이터
  • Architecture
  • 마주앙 와인
  • JsUnit
  • SyBase
  • HRA
  • Pattern
  • SQL Injection
  • 자연과학대학
  • 창강관
  • Kprobes
  • char
  • printf
  • 두뇌
  • 기회
  • Kernel
  • 마드리드
  • Multithreading
  • 웹 호스팅
  • Zlib

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 학교 과제물중 쓰레드에 대하....
    장진혁 03/17
  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • Lots of students know techn....
    Bobbi35Shannon 02/25
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  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      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.