boost::property_tree의 위험성

.ini 파일을 파싱하기 위해 boost::property_tree 클래스를 사용했었다.

서버의 성능을 테스트하던 도중 어디사 CPU를 많이 잡아먹나 계속 테스트했는데 네트워크 전송 부분이 계속 문제였다. 아무리 수정을 해도 고쳐지지 않는 상황. 비주얼스튜디오의 성능프로파일러를 돌려보니 boost::property_tree 가 문제의 원인이었다. 환경설정에서 특정한 값을 가져오기 위해 쓰느 코드가 네트워크 속도를 느리게 만드는데 기여하고 있었다.

이 부분을 수정하고나니 CPU 점유율이 아주 낮아졌다.

boost를 마구 쓰면 안된다는걸 깨닫게되었네.

boost에서 메모리풀 사용

프로그램 구현 중 메모리풀이 필요한 경우가 있어 어떻게 할까 하다가 boost의 메모리풀을 찾아보게 되었다.

boost의 메모리풀은 4가지.

  1. pool
  2. singleton_pool
  3. pool_alloc
  4. object_pool

네가지 메모리풀 중에 어떤 것이 어떤 상황에 가장 적합한지는 많이 써봐야 알 수 있을듯하다. 찾아보니 내가 가지고 있던 몇몇 게임서버 소스는 singleton_pool을 사용하고 있는 케이스가 있었다. 이것부터 먼저 찾아보는 것으로.

singleton_pool은 다른 메모리풀 클래스들과는 다르게 스레드-세이프 특성을 지니고 있어서 가장 유용하게 쓰일 것 같다.

singleton_pool을 아래와 같은 코드로 좀더 편하게 사용 가능. 출처는 ‘아지크의 좌충우돌 IT 이야기’

#include <stdio.h>
#include <iostream>
#include <vector>
#include <boost/pool/singleton_pool.hpp>
#include <boost/pool/pool_alloc.hpp>


template<typename T,  unsigned int NEXT_SIZE = 32U, unsigned int  MAX_POOL_SIZE = 0U>
class CMemoryPoolT
{
public:
     static void* operator new(size_t size)
     {
          return boost::singleton_pool<T,
               sizeof(T),
               boost::default_user_allocator_new_delete,
               boost::details::pool::default_mutex,
               NEXT_SIZE,
               MAX_POOL_SIZE>::malloc();
     }

     static void operator delete(void* p)
     {
          boost::singleton_pool<T,
               sizeof(T),
               boost::default_user_allocator_new_delete,
               boost::details::pool::default_mutex,
               NEXT_SIZE,
               MAX_POOL_SIZE>::free(p);
     }
};


class CMemoryPoolTest  :public CMemoryPoolT<CMemoryPoolTest>
{
public:
     char Dumy[124] ;
};


int _tmain(int argc, _TCHAR* argv[])
{
     using std::vector ;

     CMemoryPoolTest *p = new CMemoryPoolTest() ;

     delete p ;

     printf("Using MemoryPool... \n") ;


     return 0;
}

프로그램 종료시에는 purge_memory()를 꼭 호출해주어야 한다고 한다.

혹은 다음과 같은 방법으로도 사용 가능하다.

struct SEND_BUFFER_TAG {};
typedef boost::singleton_pool<SEND_BUFFER_TAG, SEND_BUFFER_SIZE> SendBufferPool;

사용할 클래스의 헤더파일에서 위와 같이 선언. TAG를 여러개 사용하고 메모리풀마다 다르게 적용하면 서로 다른 메모리풀이 된다.

메모리를 할당 받고 싶다면,

char* send_data = static_cast<char*>(SendBufferPool::malloc()); // 메모리를 할당 받는다.

SendBufferPool::free(send_data); // 다 사용한 메모리를 해제한다.

종료시에는 당연히,

SendBufferPool::purge_memory();

를 호출해야한다.

출처와 참고사이트

 

윈도우에서 C++ Boost 사용하기

윈도우에서 C++ 작업시 유용한 Boost 라이브러리를 사용하기 위해서는 빌드를 해야한다. 파일시스템 등을 다루는 등의 운영체제에 의존하는 기능들을 사용하기 위해 빌드해야한다고 한다.

  1. http://www.boost.org 에 들어가서 Boost를 다운 받는다.
  2. 압축을 풀고 디렉토리에 들어가 bootstrap.bat 를 실행한다.
  3. b2 –help 를 실행해서 한번 도움말을 쭉 읽어본다.
  4. 윈도우 커맨드창을 열고 해당 다음의 명령을 입력하여 빌드를 시작한다. 64비트, 디버그/릴리즈 모두, 멀티쓰레드, MPI 사용 안함으로 빌드한다.
  5. b2 variant=debug,release link=static,shared threading=multi address-model=64 –without-mpi -j8 stage
  6. 빌드 옵션은 여러가지가 더 있다. 찾아봐서 자기가 필요한대로 설정한다.
  7. -j8은 몇개의 작업을 동시에 하는지를 결정한다. 4코어인 경우에는 -j4를 해주면 모든 코어를 다 사용하게 된다. 적당하게 설정하는 것이 좋다.

빌드에는 시간이 꽤 걸린다.

다음의 링크를 참조했다.

리눅스에서 boost 라이브러리 빌드하기

부스트 라이브러리를 리눅스에서 사용하기 위한 절차를 기록해본다.

내 서버의 경우는 CentOS 6.4 버전이며 yum을 이용해 최신의 업데이트가 모두 다 되어있는 상태다.

일단 boost.org에서 최신 소스를 받는다. 이 글을 쓰고 있는 2013년 10월 14일 기준으로 1.54 버전이 가장 최신이다. unix용으로는  tar.gz과 tar.bz2 형식으로 제공되고 있는데 아무래도 압축효율이 높은 bz2 파일을 다운 받았다.

적당한 디렉토리에 받은 파일을 놓고 bunzip2 명령을 이용해 압축을 해제하면 tar 파일이 나온다. tar xvf boost_1_54_0.tar 명령을 이용해서 압축을 해제한다.

압축을 해제한 디렉토리로 들어가서 ./bootstrap.sh 파일을 실행한다.

[root@83rpm boost_1_54_0]# ./bootstrap.sh
Building Boost.Build engine with toolset gcc... tools/build/v2/engine/bin.linuxx86_64/b2
Detecting Python version... 2.6
Detecting Python root... /usr
Unicode/ICU support for Boost.Regex?... not found.
Backing up existing Boost.Build configuration in project-config.jam.1
Generating Boost.Build configuration in project-config.jam...
Bootstrapping is done. To build, run:
./b2
To adjust configuration, edit 'project-config.jam'.
Further information:
- Command line help:
./b2 --help
- Getting started guide:
http://www.boost.org/more/getting_started/unix-variants.html
- Boost.Build documentation:
http://www.boost.org/boost-build2/doc/html/index.html
[root@83rpm boost_1_54_0]#

위와 같은 메시지가 나타난다.

메시지에 나타난대로 ./b2 명령어를 입력하면 빌드가 시작된다. 내 서버의 CPU는 Xeon E3 1220 인데도… 꽤나 오래걸린다. 빌드하는 동안 CPU 사용률이 30~50% 정도를 왔다갔다한다. 대략 10~15분 정도 걸리는 것 같다.

cc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/token_ids.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/wave_config_constant.o
common.mkdir bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer
common.mkdir bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex/aq.o
gcc.compile.c++ bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/cpplexer/re2clex/cpp_re.o
gcc.archive bin.v2/libs/wave/build/gcc-4.4.7/release/link-static/threading-multi/libboost_wave.a
common.copy stage/lib/libboost_wave.a
...updated 1084 targets...
The Boost C++ Libraries were successfully built!
The following directory should be added to compiler include paths:
/backup/program/boost_1_54_0
The following directory should be added to linker library paths:
/backup/program/boost_1_54_0/stage/lib
[root@83rpm boost_1_54_0]#

한참 기다리면 위와 같은 메시지가 나온다. 부스트 라이브러리 빌드에 성공했다는 메시지와 컴파일러에서 인클루드할 경로, 라이브러리 경로를 알려주는 메시지이다.

이것으로 끝.

윈도우에서 빌드할 때는 여러가지 옵션을 넣고 한 것 같은데 리눅스에서는 너무 쉽게 끝나서 뭔가 이상하다. 혹시나 이 빌드 방법이 잘못되었다면 다음번에 수정해 나가도록 한다.

boost::thread_group

부스트의 쓰레드 그룹을 사용하기 위한 코드

출처 : http://nerv2000.tistory.com/76

#include "boost/thread.hpp"

class threadFunc
{
    int m_a;
public:
    threadFunc( int a )
    {
        m_a = a;
    }

    void operator()()
    {
        printf("[%d]일단 들어왔네!!! [%d]n", boost::this_thread::get_id(), m_a );

        Sleep(5000);

        printf("[%d] 끝났네 [%d]n", boost::this_thread::get_id(), m_a );
    }
};

int main()
{
    boost::thread_group tg;

    tg.create_thread( threadFunc(1) );                        // 1번 스래드 생성
    tg.add_thread(new boost::thread( threadFunc(2) ) );        // 2번 스래드 생성
    tg.add_thread(new boost::thread( threadFunc(3) ) );        // 3번 스래드 생성

    //모든 스래드가 종료 될때까지 대기
    tg.join_all();

    return 0;
}

Boost alt_sstream_impl.hpp warning C4819 에러 해결 방법

열심히 작업하고 빌드를 하는데 계속 warning 메시지가 떴다.

내용은

1>C:Libraryboost_1_51_0boost/format/alt_sstream_impl.hpp : warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오. (..srcbusinessservicepbbmcacheMemberInfoManager.cpp)

빌드가 안되는 것도 아니고 프로그램에 오류가 있는 것도 아니지만 뭔가해서 이 메시지를 찾아보았다.

저 메시지를 더블클릭하면 부스트의 alt_sstream_impl.hpp 파일이 열리면서 파일 인코딩에 문제가 있다고 팝업창이 뜬다. 이 파일을 열고 한참 봤지만 문제가 없어보인다. 그냥 인코딩변환해버리면 저 에러메시지가 사라지겠지만 부스트 파일을 건드리는건 여간 기분이 찜찜한지라 구글에서 검색시작.

StackOverflow에서 다음의 글을 찾았다.

http://stackoverflow.com/questions/10501634/warning-c4819-how-to-find-the-character-that-has-to-be-saved-in-unicode

글 내용을 읽어보니 alt_sstream_impl.hpp 파일에 176번 라인의 주석이 문제였다. 에휴…

해결방법은 Notepad++로 이 파일을 열고 176번 라인의 주석을 모두 지워버리고 다시 빌드해보면 위 오류 메시지가 없어진다.