멀티프로그래밍 위키로 바로가기 → http://www.devnote.net/wiki
현재 PDC 2008이 진행되고 있습니다. 직접 참가하지는 못하지만 여러 자료들이 이미 온라인에 올라와 있어 살펴볼 수 있습니다. 아래  Performance에 관련된 PPT 슬라이드 파일들이 올라와 있군요.

http://blogs.msdn.com/vancem/archive/2008/10/30/slides-for-our-all-day-pdc-2008-talks-on-performance-by-design.aspx
크리에이티브 커먼즈 라이센스
Creative Commons License

바로 전 글에서 언급한 심각한 윈도우즈 보안 핫픽스를 적용하기 위해 3시간 가량 길드워 서비스를 중단하였습니다. 물론 이번 기회에 그동안 적용하지 못한 모든 업데이트를 한꺼번에 적용하였습니다.

한 서버의 업타임을 보니 아래와 같이 무려 552일 동안 리부팅되지 않고 사용하고 있었습니다. 그러니까 이 하나의 서버만을 놓고 보면, 윈도우즈 업데이트 적용과 리부팅에 약 40분 정도 소요되었으므로 99.99% 이상의 업타임을 가졌다고 볼 수 있겠습니다. "five nines"는 아니라도 "four nines"는 되는 것 같습니다.


\\XXXX-AA00-001 has been up for: 552 day(s), 18 hour(s), 55 minute(s), 17 second(s)

크리에이티브 커먼즈 라이센스
Creative Commons License

오늘 상당히 심각한 보안 문제에 대한 패치가 마이크로소프트에서 발표되었습니다. 아래 블로그에 보다 자세한 내용이 있습니다. 아무런 인증절차 없이도 리모트로 임의의 코드를  실행할 수 있다는 것은 상당히 심각한 문제입니다.

http://blogs.technet.com/swi/archive/2008/10/23/More-detail-about-MS08-067.aspx

마이크로소프트사는 Security Development Lifecycle (SDL)이라는 이름으로 보안 문제가 있는 코드를 미리 발견하고, 공격에 취약한 부분을 미리 막는다고 하지만, 이번 예와 같은 이런 심각한 문제가 여전히 발견되고 있다는 것은 소프트웨어의 보안이 얼마나 어려운 것인가를 보여주는 예제라 하겠습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

아래 블로그 글이 재밌기도 하지만 상당히 실제 상황과도 맞는 얘기인 것 같습니다. 나중에 시간이 나면 한국어로 번역해 올리겠습니다.

http://semanticvector.blogspot.com/2008/10/more-programmers-more-code.html
크리에이티브 커먼즈 라이센스
Creative Commons License

최근에 구글은 Chrome 웹브라우저를 발표하였습니다. 그런데 흥미로운 점은 Chrome의 장점을 만화로 설명하는 온라인 책을 만들었는데, 그 내용은 전산학 OS강의를 방불케 합니다. 메모리 단편화(fragmentation)과 스레딩에 대해 설명하고 있으며 Chrome이 성능향상과 안정성을 위해 각각의 탭이 독립적인 프로세스에서 돌아간다고 합니다.

오랜동안 실행 중인 서버 프로그램이 갑자기 아무 이유없이 크래시를 일으키는 경우를 가끔 볼 수 있습니다. 그 이유 중 하나가 마찬가지로 메모리 단편화일 것입니다. 충분한 물리 메모리가 있음에도 불구하고 가상메모리가 단편화 되어 더 이상 메모리 할당이 불가능해질 수 있다는 것이지요.

그런데, 최근에 저는 또 한가지 이유를  발견하였는데 바로 스택 보호 페이지가 리셋되는 경우입니다. "단순히 정상인 메모리를 읽기만 함"으로써도 프로그램을 크래시 시킬 수 있다는 약간은 놀라운 사실입니다.

윈도우즈의 각각의 스레드 스택은 기본으로 1MB가 예약되어 있습니다. 하지만, 1MB전부가 commit (물리메모리로 매핑)된 것은 아니며, 스택 보호 페이지라는 것을 만들어 스택 크기가 커져 이 보호페이지를 액세스하게되면 예외(exception)가 발생하며, 이 때 OS 커널은 해당페이지를 Commit하고 새로운 보호페이지를 설정합니다. 아래 그림을 참고하시기 바랍니다.

사용자 삽입 이미지

이러한 방법으로 처음부터 모든 스레드에 1MB의 물리메모리를 스택으로 할당하지 않아도 되기 때문에 메모리 낭비를 상당히 줄일 수 있습니다.

문제는 어떤 특정 스레드의 스택 보호 페이지를 다른 스레드나 프로세스에서 읽기를 시도하는 것만으로도 보호 페이지가 리셋되어 사라지게 되며 이 경우 재설정이 되지 않고 스택크기도 늘어나지 않습니다.

보호 페이지가 사라진 상태에서 당장 문제가 나타나지는 않으나, 나중에 스택 보호 페이지가 없는 스레드가 스택을 많이 사용하게 되어 보호 페이지와 그 위의 commit되지 않은 페이지를 액세스하게 되면 Access Violation나며 어플리케이션이 종료될 가능성이 높습니다. 어플리케이션의 예외처리기 (unhandled exception handler)를 사용하여 오류 분석을 해봐도 원인을 찾기는 쉽지 않습니다.



이 문제를 실제로 보여주는 예제가 아래에 있습니다. 아래 코드를 복사하여 BrokenGuardPage.cpp라는 이름으로 저장한 다음, "cl BrokenGuardPage.cpp"와 같이 컴파일하면 예제 실행파일을 만들 수 있습니다.

AccessStackGuardFromOtherThread 함수는 새로운 스레드 하나를 생성하고 있으며 지역변수의 포인터를 새로운 스레드에 전달합니다. 새로 생성된 스레드는 전달된 지역변수 메모리값에 -0x2000을 하여 스택보호 페이지에 대해 읽기 만을 시도합니다.

이 프로그램을 실행하면 프로그램 STATUS_GUARD_PAGE_VIOLATION 예외가 먼저 발생합니다. 이 때 Unhandled exception handler가 설정되어 있어 프로그램은 종료하지 않고 계속실행이 됩니다. 다음으로 Crash 함수가 main 스레드로 부터 호출되는데, Crash는 단순히 큰 지역변수를 가지고 이를 초기화하려고 시도하고 있습니다. Crash 함수에 잘못된 코드는 전혀 없습니다만, Access Violation을 발생하며 프로그램이 종료되어 마지막의 "printf("End of Program.\n")"는 실행되지 않습니다.


////////////////////////////////////////////////////////////////
//
//  BrokenGuardPage.cpp
//
//  Just use following commands for compile:
//      cl BrokenGuardPage.cpp
//
//  www.devnote.net (9/26/2008)
//
////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <process.h>
#include <windows.h>

//--------------------------------------------------------------
void Crash () {
    printf("Crash\n");

    // This function simply allocate a big local array and initalizes first element
    char test[32000];
    test[0] = 0;
}

//--------------------------------------------------------------
static unsigned __stdcall ThreadProc (LPVOID param) {
    printf ("ThreadProc\n\tTry to access Stack Guard Page\n");

    // main thread's local variable
    char * ptr = (char *)param;

    ptr -= 0x2000;

    // Just try to read stack guard page
    volatile char ch = *ptr;

    return 0;

}

//--------------------------------------------------------------
static void AccessStackGuardFromOtherThread () {
    printf("AccessStackGuardFromOtherThread\n");

    unsigned localVar; 
    HANDLE exceptionThread = (HANDLE)_beginthreadex(
        NULL,
        0,          // stack size
        ThreadProc,
        &localVar,  // Pass local variable pointer
        0,          // suspended = false
        NULL
    );
   
    // Wait for the thread finish
    WaitForSingleObject(exceptionThread, INFINITE);
}

//--------------------------------------------------------------
static LONG WINAPI OurUnhandledExceptionFilter (EXCEPTION_POINTERS * ep) {
    printf ("OurUnhandledExceptionFilter: exception code = %X\n", ep->ExceptionRecord->ExceptionCode); 
    if (ep->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION)
        printf("STATUS_GUARD_PAGE_VIOLATION :%0X\n", ep->ExceptionRecord->ExceptionInformation[1]);
    return EXCEPTION_EXECUTE_HANDLER;
}

//--------------------------------------------------------------
void main () {
    SetUnhandledExceptionFilter(OurUnhandledExceptionFilter);
    AccessStackGuardFromOtherThread();
    Crash();

    printf("End of Program.\n");   // This will never be called
}


인터넷을 검색해보니 이미 이 문제에 관해 아래와 블로그 글들이 올라와 있군요.

http://blogs.msdn.com/oldnewthing/archive/2006/01/17/513779.aspx

같은 프로세스에서 뿐만 아니라, 읽기 메모리 권한(PROCESS_VM_READ)을 다른 프로세스에 부여하는 것만으로도 똑같이 프로그램 크래시를 유발할 수 있습니다. 또한 예외처리 핸들러에서 가끔 사용되는 IsBadxxxPtr API들도 똑같은 문제를 유발시킵니다. 아래 블로그를 참고하시기 바랍니다.

http://blogs.msdn.com/larryosterman/archive/2004/05/18/134471.aspx

크리에이티브 커먼즈 라이센스
Creative Commons License

Cilk 웹페이지

분류없음 2008/09/29 03:57
Cilk는 약 15년전부터 MIT에서 시작된 프로젝트로, 효율적인 멀티스레드 프로그래밍 언어 (특히 스케줄링 알고리즘 적용)를 개발하는데 상당한 성과를 이루어 냈습니다.

최근에는 마이크로소프트 Microsoft Parallel FX Library (이 글을 참고하세요)가 매우 비슷한 개념과 문법을 .NET에 적용하기도 하였습니다.

Cilk 개발팀은 마침내 스핀오프하여 회사를 차렸는에 아래 웹페이지가 그 회사의 홈페이지입니다. 여러 가지  흥미로운 문서들도 많이 있어 소개합니다.

http://www.cilk.com/
크리에이티브 커먼즈 라이센스
Creative Commons License

C++에서 local static 변수를 사용할 경우, 멀티스레드 프로그램에서 이른바 race condition이 생길 가능성이 있습니다. 이에 관해 아래 블로그에 자세한 설명이 나와 있습니다.

http://blogs.msdn.com/oldnewthing/archive/2004/03/08/85901.aspx

위 페이지의 첫번째 예제같이 보통 단순한  전역 bool 값을 사용하는 경우는 쉽게 문제를 알아낼 수 있지만, static object를 함수 안에 사용하는 경우 컴파일러가 내부 최적화하는 과정에서 전역변수 (두번째 예제의 "constructed")를 만들어 내기 때문에, 모르고 지나칠 가능성이 많습니다.

그러니까, 특히 C++를 사용한 멀티스레드 프로그램에서는 local static 변수를 사용을 자제하는 것이 좋겠습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License

아래 좋은 윈도우즈 고성능 어플리케이션에 관한 문서를 발견하여 링크를 복사하였습니다.

http://blogs.technet.com/winserverperformance/archive/2008/04/25/designing-applications-for-high-performance-part-1.aspx

http://blogs.technet.com/winserverperformance/archive/2008/05/21/designing-applications-for-high-performance-part-ii.aspx

http://blogs.technet.com/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
크리에이티브 커먼즈 라이센스
Creative Commons License

코맨드라인 디버거인 NTSD, KDB 등을 사용하다보면 전체 스레드의 스택을 살펴 보는 (~*kb) 일을 자주하게 됩니다. 이럴 때면 여러 스레드 콜스택 중에서 특정 함수 호출 부분을 모두 찾는 다거나 특정 모듈을 찾을 경우가 많은데, 커맨드 콘솔의 텍스트 출력을 눈으로 훑어 나가기가 쉽지는 않습니다.


아래와 같은 레지스트리를 설정하면, 콘솔 창에서 "마우스로 원하는 스트링을 선택한 후" 1, 2, 3, 4 중 하나의 방법을 사용하여 색깔을 변경할 수 있습니다. 특히 3과 4가 디버깅 중에 매우 유용합니다.


[HKEY_CURRENT_USER\Console]

"QuickEdit"=dword:00000001

"EnableColorSelection"=dword:00000001     


1.       Alt + [0..9] : 텍스트 색깔 설정

2.       Ctrl + [0..9] : 배경색 설정

3.       Alt + Shift + [0..9] : 선택된 스트링과 같은 모든 스트링의 텍스트 색깔 설정

4.       Ctrl + Shift + [0..9] : 선택된 스트링과 같은 모든 스트링의 배경 색깔 설정

크리에이티브 커먼즈 라이센스
Creative Commons License