CPPCon 2016 The strange details of std::string at Facebook

동영상 링크
ppt링크

뭐가 제일 페이스북에 효율적인지

string은 제일 중요한 요소중 하나
cpu전체의 18%가 std안에서 쓰임

string을 간단하게 만드는 것

gcc string(v < 5) Implementation

sizeof string is 8 (in gcc same as pointer)
다른 모든것보다 제일 많이 쓰이는 string? => empty string
but empty string is no empty
malloc을 해서 매 번 overhead를 감수하고 할껀가?
gcc는 매번 25byte arry를 가지고 있음 So empty is not empty

Q:왜 empty가 없는건데?
A:그러면 매 번 비어있는 string인지 체크해야함 if NullString || ptr != null_ptr 등등

gcc copy on write
copy 생성자를 받을때 original string의 레퍼런스를 하나 증가시킴 그후 메모리를 수정시킬때만 write함
(지금은 c++11 concurrency문제 때문에 drop)


fbstring

string관련 처리 코드에서 병목현상이 발생

  • 다른 페이지를 매번 접근
  • malloc에서 걸림

매번 힙을 사용하다 보니 문제가 생겨서 작은 사이즈의 string의 경우 스택을 사용해서 최적화를 진행

fbstring 구조

Normal String : data | size(14) | capacity(15) (data제외 29 바이트)

union

Small String : data \0 .... emty size (25바이트)

union으로 되어있기 때문에 small string의 사이즈를 넘어가게 되면 normal string으로 넘어가게 됨
이런 방식으로 하면 마지막에 널바이트로 덮으면서 남은 capacity도 표현 가능… 개똑똑)


최적화

  • normal string인지 small string인지 구분할 flag가 필요.
    facebook 에서는 JEmalloc이라는 메모리 할당을 씀
    bucket에서 쓸 수 있는 메모리를 리턴해주는데
    8byte align을 해서 29byte를 요청하면 32byte를 리턴해 줌.
    fbstring은 이 사실을 알고 있기 때문에 남은 3바이트를 flag에 사용하는 비트로 이용함
  • 일정 사이즈 이상 커지면 big size string으로 해서 ref conut를 사용(Copy on Write)

Performance of fbstring

gcc_string.size()

movq (%rdi), %rax
movq -24(%rax), %rax

fbstring.size()

movabsq $-4611686018427387904, %rax
testq %rax, 16(%rdi)
je .L7
----is_small-----
movq 8(%rdi), %rax
ret
.L7:
movsbq 23(%rdi), %rdx
movl $23, %eax
subq %rdx, %rax
ret

딱봐도 fbstring이 훨씬 길다.
small string인지 normal string인지 구분을 먼저하고 길이를 리턴 해야 하기 때 문에 라인 수도 더 길다.

근데 밴치마크를 하게 될 경우
gcc string : 1.6ns
fb string : 0.9 ns
???? 브랜치 까지 있는 9줄의 코드가 어떻게 하면 2줄짜리 코드보다 더 빠를 수 있지????

-> gcc string은 모두 힙을 쓰기 때문에 page fault가 자주 일어나게 됨 align된 string사이즈라면 fault가 더 적게 나서 fbstring보다 빠르지만 일반적인 경우 fbstring이 더 빠름

그래서 std::string 을 folly::fbstring으로 교체 해봤다.
-> 1% 성능향상 (적은것 같아 보일 수 있지만 fb에서 사용하는 모든 c++의 성능이 1%향상 되었다고 보면.. 티끌모아 태산이다. )

Killing the null terminator

fbstring lazily wrote \0

보통 string을 쓰나보면 push_back을 이용해서 concat하는 경우가 많음.
그래서 굳이 계속 \0을 붙여줄 필요 없이 필요할 때만 붙여줌
But this is illegal (표준에 맞는 구현이 아님 Concurrency를 생각하면 좋은 구현 X)
하지만 대부분의 사람은 null에 굳이 상관 없는 코드를 작성 하기 때문에 그냥 씀
c_str(), data()는 \0을 붙이게 됨

Problem in c_str()

const Char * c_str() const {
...
data[size()] = ‘\0’;
return data;
}

fb에서는 global read only string 변수를 두고 다양한 쓰레드에서 c_str()을 호출한다.
c_str은 구현대로 라면 const함수이기 때문에 원본 데이터에 대해서 변경이 없어야 함.
프로그래머 입장에서 보면 const라 데이터에 변화가 없다고 생각하지만 Cpu입장에서 보면 string마지막에 \0를 붙임으로써 cache line을 다 날려버린다..! 느려질 수 밖에

그래서 \0이 있는경우는 체크해서 data에 안쓰기로 결정!

const Char * c_str() const {
...
if (data[size()] != ‘\0’) //Problem Undefined behavior  
data[size()] = ‘\0’;
return data;
}

위에 저 if 안의 diff는 broken code.
초기화 되지 않은 메모리를 읽을 수 도 있음.
문자열 길이가 128바이트라면 129byte의 메모리가 필요함.
근데 je malloc에서 malloc을 하게 될 경우 128이란 숫자는 페이지 크기에 align 시키기 편한 숫자(gcd 4096 92) 이라 페이지의 맨 마지막(page last - 128)에 배치.

다른 97같이 align안 맞는 경우는 ok(뒤에 align을 맞추기 위해 보통 몇바이트 더 할당되기때문에)
128byte를 할당하면 페이지 맨 끝 부분에 할당되게 되면서 남는 메모리 공간이 없게됨

문제가 되는 부분은 if문

if(data[size()]==0)

data[size()]에 read 하게되면 129번째인데 할당되지도 않고 쓰지도 않은 메모리에 접근하게됨

근데 커널에서 Undefined mem(할당되지 않고 write도 안한 경우)에 접근하게되면 0을 리턴함. 그렇기 때문에 저 if문이 broken이라는 표현을 쓴듯
그래서 Null을 안쓰고 포인터를 리턴하게되고 write를 하게되면 믈리 페이지가 맵핑되면서 129번째에 널이 없는채로 리턴. 문자열 관련처리를 하다가 널을 찾아 3만리 떠날 수 있는 큰 문제

저작자 표시 비영리 변경 금지
신고

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글  3개가 달렸습니다.
  1. 이해가 쏙쏙되어요! 감사합니당 천사 건씌
  2. 정말 감사합니다 ! ^^ 오늘 행복한 하루 지내세요 ㅎㅎ
  3. 코잘남이되고싶어요 2017.04.05 17:53 신고
    역시 갓건! 정말 감사해요~
secret

C++11 부터 가변인자 템플릿(variadic template)을 지원하게 되면서 tuple의 구현이 재미있어졌다.

가변인자 템플릿을 지원하기전의 tuple은 최대 10개의 타입을 받는 것 까지 가능했다고 한다.
왜그러냐 하면 아래와 같이 N개 까지의 클래스를 모두 따로 정의해 뒀기 때문이라고 한다...
(VC2010기준 아래는 boost의 tuple)
tuple_macro

C++11 가변인자 템플릿을 이용할 경우 이런식으로 구현 할 수 있다. 

vs2015에 implemetation된 tuple클래스 인데 그냥 최소한의 소스만 가져왔다.
tuple의 각 value는 tuple_val에 저장한다.
tuple class같은 생성자에서 상속 받는 방법을 이용하여 recursive specialization을 사용해 모든 인자들에 대해 specialization을 할 수 있게 해준다.

1, 2, 3, 4 가 있으면
this-1 rest(2,3,4)
this-2 rest(3,4)
this-3 rest(4)
this-4
이런 식으로 진행된다고 생각 하면된다.

+

오늘의 교훈
소스가 막막하면 최소한 동작으로 줄이고 보자
답이 나온다

신고

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

fgets vs ReadFile

공부/c++ 2015.07.28 18:06

결론 WriteFile이 더 빠르다



저작자 표시 비영리 변경 금지
신고

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글 하나 달렸습니다.
  1. 더큰파일도 테스트 해보고 싶었으나 이상하게 무한루프를 돌아서 계속 파일사이즈만 커진다..
    이 문제는 추후 수정하는걸로
secret

https://github.com/jen6/SuspendThread


사실 별건 아니고 기존 std::thread 같은 경우 쓰레드를 만듬과 동시에 돌아가게 된다.

그게 싫을 때도 있으니 일단 만들어 놓고 내가 원할 때 쓰레드가 시작될 수 있도록 해놓았다.(다시 멈추는건 안된다!)

사실 이동대입연산자도 만들어야 하고 native handle 반환하는 메서드도 하나 따로 빼야하고 프로젝트 구조도 vs뿐만 아니라

linux에서도 사용 할 수 있도록 변경해야 하지만...

언젠간 하겠지뭐

저작자 표시 비영리 변경 금지
신고

'공부 > c++' 카테고리의 다른 글

C++11 tuple implementation  (0) 2015.12.30
fgets vs ReadFile  (1) 2015.07.28
github에 공개한 Suspended Thread  (0) 2015.06.06
C++ 유틸리티 혹은 자료공개용 svn  (0) 2015.03.23
메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

http://makeall.ml/svn

id:anon pw:anon

저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

fgets vs ReadFile  (1) 2015.07.28
github에 공개한 Suspended Thread  (0) 2015.06.06
C++ 유틸리티 혹은 자료공개용 svn  (0) 2015.03.23
메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

이번에 어셈 시뮬레이터 만들면서 너무 고생해서 정리할겸 한번 올립니다


using namespace std;


typedefine int(test::*_func)();


class test{

public:

int print();

}


int test::print(){

cout << "test" << endl;


int main(int argc, char * argv[])

{

test t;

_func func;

func = &test::print;

(t.*func)();

return 0;

}


함수포인터 유의할점

1.함수포인터 형식 typedefine할떄 스코프 지정 연산자를 꼭 써줘야함

2.함수정의를 해줘야함(이것 때문에 몇일 고생함..)

3.함수를 호출할때 test에 func라는 함수는 없기때문에 역참조 연산자를 꼭 붙여줘야함


저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

github에 공개한 Suspended Thread  (0) 2015.06.06
C++ 유틸리티 혹은 자료공개용 svn  (0) 2015.03.23
메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret
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
#include <stdio.h>
#include <Windows.h>
#include <atlstr.h>
#include <tchar.h>
#include <locale.h>
 
int main()
{
    WIN32_FIND_DATA FindData;
    HANDLE hFind;
    CString path (_T("C:\\*"));
 
    _wsetlocale(LC_ALL, _T("korean"));     
 
 
    hFind = FindFirstFile(path, &FindData);
    if (hFind == INVALID_HANDLE_VALUE)
        return 0;
 
    do
    {
        _tprintf(_T("%s\n"), FindData.cFileName);
    } while (FindNextFile(hFind, &FindData));
 
    FindClose(hFind);
 
    return 0;
}
 

유니코드에서 애를좀 많이 먹었다


찬호행님 사랑해요~

저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

C++ 유틸리티 혹은 자료공개용 svn  (0) 2015.03.23
메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16
boost access in to all directory  (5) 2014.05.15

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

api handle?

공부/c++ 2014.05.16 11:38
설명의 편의를 위해 경어는 생략하겠습니다.)
(저도 여기저기서 주워들은 것이라서 틀린점이 있을 수 있습니다. 지적해 주시면 정말 도움이 될 것입니다.)

정확한 통계가 있을리는 만무하지만.. 많은 사람들이 윈도우 개발을 처음 접하면 몇가지 의문점이 (실제로는 산더미같이!!!) 생기게 된다.

제일 먼저 메인함수를 접하게 되는데, 콘솔에서의 메인이라 해봐야 짧으면 "void main()" 뿐이니 몇자 되지도 않고 간단하다.

그런데.. 처음 접하게 되는 윈도우 메인함수는..


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, ... )

아닛! 메인부터 벌써 가드가 철저하다!

대체!! APIENTRY는 무엇이며 HINSTANCE는 또 무엇이란 말인가???

놀란 가슴을 부여잡고 도움말을 찾기 위해 HINSTANCE 위에서 F1을 누르거나..

자립심이 약간 결여된 사람들은 브라우저를 열고 이름은 밝힐 수 없지만 X이버 지식X에 가서 검색을 한다...


MSDN -> 인스턴스의 "핸들" 입니다. (설명 참 짧다. 이런 뻔한걸 왜 물어보냐는 투다.. ㅇㅅㅇ);;

지식X -> HINSTANCE란 프로그램의 모듈을 담고 있는 "핸들"로서..


핸들..?? 아니 대체 핸들은 또 뭐야~(산넘어 산이다) 하며 다시 검색해본다.

MSDN -> 핸들은 오브젝트여요~
( 앞산이 어디에 있냐? 뒷산 앞에 있어~ 그럼 뒷산은 어딨는데? 앞산 뒤에 있지~ 라는것 같다)

지식X -> "06년식 트라제 사제오디오 설치시 핸들리모컨 사용이.."
(헉!! 깜짝 놀라며 api 핸들로 다시 검색해본다..;;)


(다시 검색된 지식X 결과)
-> 윈도우에서 다루는 자원번호로... 주민등록번호와 같은 어쩌고 저쩌고..
-> 말그대로 핸들입니다.. 운전하는 사람이 자동차 구조를 알필요가.. 어쩌고 저쩌고.. (결론은 알필요 없는 소리)
-> (일단 영어의 뜻을 살펴보자며 사전을 복사해다 긁어놓고..) 이뜻에서 유추해보건데.. 이러쿵 저러쿵.. 핸들을 통해서 컨트롤의 속성을 조절.. 어쩌고 저쩌고.. 일종의 메모리 번지값에 대한 주소..
(결론은 틀린소리...;;)


아니.. 그러니까 대체 뭐라는 거야.. ㅇ_ㅇ);;;


역시나 이름은 밝힐 수 없지만 이곳 홈주인이신 김모상형님이 쓰신 책의 내용을 요약해 보자면..

(1) 운영체제가 발급해 주는 것을 받아서 쓸 뿐, 직접 만들 수는 없다.

(2) 대상을 빠르게 구분하기 위해 정수형을 사용하며 중복되지 않는다.

(3) 파일, 브러쉬, 펜, 폰트 등을 모두 핸들을 붙여 번호로 관리한다.

음.. 그럼 이 내용을 정리해보자면..


"내가 파일이나 폰트를 만들어달라고 OS에게 요청을 하면, OS는 이것들을 만든 후에 중복되지 않는 핸들이라는 고유 ID를 만들어 붙이고, 만든 파일이나 폰트를 직접 주는 것이 아니라, 핸들만 건내주는 것이구나" 라는 것을 알 수 있다.

(우선 여기까지의 내용이 기억나지 않으면 옆 API강좌의 1-3-나. 핸들에 대한 이해를 읽고오자)
자.. 이제 핸들이라는 것은 "파일이나 폰트, DC, 브러쉬, 펜 등등의 각종 [!]오브젝트 에 대한 일종의 참조 번호"라는 것은 이해할 수 있을 것이다.

어라? 그러고 보니 MSDN의 "핸들은 오브젝트여요" 라는 소리가 틀린말만은 아니다.


그렇다면 왜 파일이나, 폰트, 펜등의 오브젝트를 직접 주지않고 이렇게 복잡한 방식을 취했는지 생각해보자.

( 아니.. 생각해보자고 했는데 생각하지 않고 스크롤 내린사람은 반성하자 ㅡㅅㅡ);;



그렇다.. 다들 짐작했겠지만 모 CF의 광고처럼 "오브젝트는 소중하니까요~" 일 것이다.

약간은 맞지 않는 측면이 있지만 다음의 예를 통해 알아보자.


자, 당신은 공무원이고 도로공사에 필요한 공금 수백억이 정부로부터 당신에게 "직접" 주어졌다면 어떻게 할것인가?

"공금은 투명하고 안전하게 관리되어야 하니 지금 당장 쓸돈이 아니면 은행에 보관한 후에 공개입찰을 통해서 건설사를 선정하고 비용을 사용할때마다 영수증을 받고 출금내역을 기록할 것이다."
( 우와! 이런분이 있다면 정말 존경스럽다. ㅇ_ㅇ);; 법없이도 살 분이다!!)


나라면(다른 분들도 비슷하겠지만.. ㅡㅅㅡ);; 다른 직원들 몰래 공금을 몽땅 들고 해외로 튄다거나..

하루이틀에 걸쳐 사용할 금액이 아니니, 일정 금액을 몰래 빼돌려 CMA 계좌라도 개설해서 거기다 넣고 이자를 받아 챙기거나

입찰시에 건설사와 짜고 공사비를 부풀린 후에 부풀린 금액을 리베이트로 받을 것이다.

또한 이렇게 공금을 달라는 대로 담당자에게 직접 이사람 저사람 주다보면 누구에게 얼마를 주었는지, 얼마를 받아야 되는지 정부에서는 관리도 되지 않는다.


여기서 비유한 공금은 오브젝트(파일, 펜, 폰트 등등) 이고, 정부는 OS라고 생각하면 된다.

사방 팔방에 흑심품은 사람 천지니 어디 믿고 공금을 전부 맡기겠는가? 그럴수는 없다.

공공계좌를 개설한 후에 입금을 시키고, 계좌를 통해서만 입출금이 가능하게 하고, 입출금 내역은 정기적인 감사를 통해 투명성을 확보한다.


이러한 방식을 취함으로서 공금(오브젝트)의 안전성과 투명성, 그리고 정부(OS)에서는 공금(오브젝트)이 어떻게 사용되고 있는지 관리하기가 편하다.

이제 오브젝트를 직접 주지 않는 대략적인 이유가 이해가 되었을 것이다.

"파일이나 폰트등의 오브젝트(공금)는 안전한 관리를 위해 직접 넘기지 않고, 핸들ID(계좌)를 통한 참조만 가능하게 해놨구나" 라는 것을 알 수 있다.


여기까지의 내용을 정리하자면.

"OS는 오브젝트를 생성한 후에 중복되지 않는 정수형의 ID를 핸들값으로서 부여한 후 프로세서에 넘김으로서 오브젝트의 안정성을 확보하고, 프로세서는 이 핸들을 받아 생성된 오브젝트를 자유롭게 [!]참조 할 수 있다. "
이번에는 핸들의 특성에 대해 알아보자.

역시나 이번에도 이름은 밝힐 수 없지만, 김모상형님이 쓰신 책의 내용중에 다음과 같은 내용이 있다.
(이거 무단으로 전제하는건데.. 잡혀가는거 아닌지 모르겠다.. ㅠ.ㅠ);;;

----------------------------------------------------------------------------------------
26-1-가. 파일 핸들도 메모리를 차지하고..(중략) 사용하고 난 후에 해제하는 것이 원칙이다. 파일을 닫지 않았더라도 프로그램이 종료될 때 열려진 모든 파일은 [!]자동으로 닫혀지지만...
40-2-나. 프로세스가 종료될 때는 다음 일련의 작업이 이루어진다. (중략) [!]모든 열려진 핸들을 닫는다.
----------------------------------------------------------------------------------------

아니! 이 내용을 보니 "프로세스 종료시에 알아서 핸들이 닫혀진다" 고 한다. 그렇다면 다음 예제들을 한번 살펴보자.

예) 타이머 사용과 제거.
hTimer = (HANDLE)SetTimer(hWnd,1,1000,NULL);
// 타이머 사용후.
// KillTimer(hWnd,1); <- 필요없는 코드 ?

예) DC를 얻고 펜을 작성한 후에 제거.`
hdc=BeginPaint(hWnd,&ps);
MyPen = CreatePen(PS_SOLID, 5, RGB(0,0,255));
OldPen = (HPEN)SelectObject(hdc, MyPen);
Rectangle(hdc,50,50,300,200);
SelectObject(hdc, OldPen);
//DeleteObject(MyPen); <- 필요없는 코드 ?
//EndPaint(hWnd,&ps); <- 필요없는 코드 ?

(1) 종료시에 알아서 모든 핸들을 자동으로 닫는다면, 열려져 있는 얼마 안되는 핸들의 메모리가 무시할 정도라면 KillTimer나 DeleteObject등은 필요하지 않는것 아닌가?


다른 생각도 한번 해보자. "모니터링 프로그램을 실행시켜주는 실행 프로그램(1개)과 모니터링 프로그램들(n개)"을 작성한다고 가정해보자.

실행프로그램이 먼저 동작하고, 사용자의 입력에 따라 각각의 독립된 프로세스인 모니터링 프로그램들을 실행시킨다.

자~ 당신은 폰트, 브러쉬, 펜등을 작성하여 실행프로그램의 UI를 멋지게 꾸민후 작성을 완료했다.

다음으로 n개의 모니터링 프로그램을 만들려고 생각해보니 이런 생각이 든다.

어차피 모니터링 프로그램들은 실행 프로그램이 먼저 실행되어야 한다.
그렇다면 모니터링 프로그램들에서 제각각 폰트, 브러쉬, 펜을 작성하느니, "실행 프로그램에서 이미 만들어 놓은 폰트, 브러쉬, 펜들의 핸들을 받아 사용"하면 리소스도 절약되고, 코딩도 간결해지지 않겠는가!! 우와! 나이쓰 아이디어!!!!!

(2) 실행프로그램의 폰트, 브러쉬, 펜등의 핸들을 모니터링 프로그램들의 실행인자로 넘겨줘 사용하도록 만들었다.


한김에 가정을 하나 더 해보자. 사용자가 색이나 선굵기를 지정하면 펜과 브러쉬를 만들고 마우스 클릭에 따라 원이나 사각형을 그려주는 초간단 그림판을 만들었다.

그림판을 만들어 사용자에게 보내니, "아니 그린 내용을 저장하고 불러오는 기능도 만들어 주셔야죠" 라고 하기에 다음과 같이 저장하고 로드하도록 만들었다.

(파일 저장을 위한 구조체 선언)
typedef struct {
int nType; //0이면 원 1이면 사각형
HBRUSH hBrush; // 브러쉬 핸들
HPEN hPen; // 펜 핸들
int sx; // 시작점 x
int sy; // 시작점 y
int ex; // 종료점 x
int ey; // 종료점 y
}DrawInfo;

DrawInfo dwInfo;
dwInfo.hBrush = MyBrush;
dwInfo.hPen = MyPen;
(어쩌구저쩌구...)

(파일 저장)
WriteFile(hFile, &dwInfo, sizeof(DrawInfo), &dwWritten, NULL);

우와~! 퍼펙하다. 사용자가 만든 브러쉬와 펜 정보를 저장하고, 시작점과 끝점 도형의 종류까지 저장하니 완벽하다.

WriteFile();로 파일에 저장을 한후 파일을 확인해 보니 브러쉬부터 시작점, 종료점 등등 모든 값들이 제대로 들어가 있다.

자, 이제 로드를 만들어 볼까?

(파일 로드)
ReadFile(hFile, &dwInfo, sizeof(DrawInfo), &dwRead, NULL);

hdc = BeginPaint(hWnd,&ps);
OldBrush = (HBRUSH)SelectObject(hdc, dwInfo.hBrush);
OldPen = (HPEN)SelectObject(hdc, dwInfo.hPen);
if(dwInfo.nType == 0) {
Ellipse(hdc, dwInfo.sx, dwInfo.sy, dwInfo.ex, dwInfo.ey);
} else {
Rectangle(hdc, dwInfo.sx, dwInfo.sy, dwInfo.ex, dwInfo.ey);
}

(3) 우와~! 퍼펙 할까?


(1)번의 경우는 자료 부족 및 능력 부족으로 인해 "확신 할 수는 없지만" 프로세스 종료시 타이머나 파일, 폰트등의 오브젝트는 자동으로 소멸된다고 생각한다.
(혹시 정확한 내용을 아시는 분은 증빙 자료 및 소견서를 200자 원고지 100매 이내로 써서 보내지 않으셔도 되니..ㅠㅠ 알려주시면 감사하겠습니다.. __);

앞서 공사비로 비유했지만, 정부(OS)에서 공사비를(오브젝트) 계좌에 넣어 목록으로 관리하니, 공사가 끝났다면 해당 계좌를 회수 할 것이다.

나중에 나오겠지만 오브젝트에 핸들을 붙여 관리하려면 당연히 "핸들 리스트가" 존재할 것이고, 이 리스트가 존재함으로서 OS는 종료된 프로세스에 관련된 오브젝트는 파괴할 것이다.

물론 자동으로 파괴하니 CloseHandle하지도 말고 DeleteObject() 할것도 없이 편하게 코딩하자! 라는 뜻은 아니다.

이러한 코딩이 좋지 못하다는 것은 누구나가 아는 사실이고, 여기서 말하는 요점은 이런 "특징" 이 있다는 것이지 "옳은 방식"은 아니라는 것을 잊지말자.


(2)번의 경우를 보고 "우와~! 정말 굿아이디어다"라고 생각하신분 설마.. 없으시기를 바란다.. -_ㅡ+

"오브젝트가 소중"하기 때문에 핸들로 관리를 하는건데, 핸들번호만 안다고 해서 개나소나 다 가져다가 오브젝트를 쓴다면 이런짓을 뭐하러 하겠는가?

앞서 나온 공사비로 예를 들자면, "계좌번호"만 안다고 해서 아무나가서 돈을 달라고 하면 돈주는 은행이 있겠는가? 그렇다면 돈을 땅에 파묻어놓고 쓰지 뭐하러 은행에 맡기겠는가?

"핸들은 다른 프로세스에게 넘길 이유도 없고, 넘겨봐야 쓸 수가 없다"


그렇다면 (3)번의 경우는 어떠할까?

다른 프로세스에 넘기는 것이 아니고, 자신의 프로세스에서 생성한 오브젝트의 핸들 ID를 파일에 보관했다가 사용하는 것이니 전혀 문제 될 것이 없어 보이긴 하다.

하지만, 핸들이라는 것은 만들어 놓은 오브젝트를 참조할 번호일뿐 "오브젝트 자체"가 아니라는 것은 우리 모두가 이미 알고 있다.

내가 만든 그림판이 실행중에 브러쉬를 만들어 브러쉬의 핸들을 저장했다면, "브러쉬라는 오브젝트는 이미 만들어져 있기" 때문에 핸들값을 어디에 저장했다 꺼냈는가와 관계 없이 브러쉬라는 오브젝트를 참조 할 수 있다.
(정부로부터 공사비 계좌를 받을때 같이 만든 현금카드를 벽장에 넣어놓았다고 해서 ATM을 이용 못하고, 금고에 넣어놓으면 이용할수 있는가? 이건 말도 안된다~!)

하지만 파일에 핸들값을 저장한 후에 그림판이 종료되면 어떻게 될 것인가? 내가 파괴를 하건 하지 않았건, OS에서 알아서 "브러쉬 오브젝트를 파괴" 할 것이다.

다시 그림판을 실행시킨 후에 파일에 저장했던 핸들값을 읽어들여 봐야 "브러쉬라는 오브젝트는 이미 파괴" 되었으니 핸들값이 의미가 있겠는가?
(앞서 받은 현금카드로 ATM에서 언제든지 편리하게 돈을 뽑아 공사비를 지불했다. 그런데 공사가 끝나 정부에서 계좌를 없애버렸는데도, 현금카드가 있으니 돈은 나오겠는가?)


자.. 이제 요점을 정리해보자.

(1) 특정 프로세스가 오브젝트 생성을 요청하여 받은 핸들은 무언가의 "핸들 리스트"로 관리될 것이다.
(2) OS는 프로세스가 종료되면 "핸들 리스트"를 보고 생성되어 있는 오브젝트를 모두 파괴한다(가정)
(3) 폰트, 펜, 브러쉬를 생성하여 받은 핸들값은 다른 프로세스에 넘겨봐야 의미가 없다. ([!] 모든 핸들이 의미가 없는것은 아니다. 일단은 이렇게만 알아두자)
(4) 핸들은 오브젝트에 대한 참조ID 일 뿐이므로 오브젝트가 파괴된 후, 해당 핸들값은 의미가 없다.

출저 soen.kr


저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

메소드 포인터(멤버 함수 포인터)  (0) 2014.08.04
win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16
boost access in to all directory  (5) 2014.05.15
boost directory접근  (0) 2014.05.15

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

http://bbolmin.tistory.com/67 //파일관련


http://soen.kr/ // 윈도 api에 대한 전반적인 설명


http://minilog.tistory.com/35


http://msdn.microsoft.com/en-us/library/ff818516%28v=vs.85%29.aspx


http://www.relisoft.com/win32/ //튜토리얼


http://www.winprog.org/tutorial/



http://msdn.microsoft.com/en-us/library/windows/desktop/aa365530%28v=vs.85%29.aspx



http://stackoverflow.com/questions/2314542/listing-directory-contents-using-c-and-windows //소스 예제


http://bytes.com/topic/c/answers/869208-list-files-directory

http://www.relisoft.com/win32/watcher.html


http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418%28v=vs.85%29.aspx
find first file

http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa364428%28v=vs.85%29.aspx
find next file

http://blog.naver.com/PostView.nhn?blogId=hsshee&logNo=70037789119
findfile 에 대한 설명


http://ezbeat.tistory.com/134


http://j07051.tistory.com/108

Cstring


http://msdn.microsoft.com/en-us/library/aa300688%28v=vs.60%29.aspx

Cstring msdn


http://ntcoder.com/bab/2009/03/31/check-directory-or-folder-empty-status/

폴더가 비었는지 아닌지

http://msdn.microsoft.com/en-us/library/windows/desktop/bb773623%28v=vs.85%29.aspx


http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa365740%28v=vs.85%29.aspx

win32_find_data struct


http://jangjy.tistory.com/entry/LPCSTR-LPCTSTR-const-char-CString-%EB%93%B1%EB%93%B1-%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%98%95

LPSTR, LPCSTR, LPTSTR, LPCTSTR, LPWSTR 의 의미


http://pmguda.com/408

제대로된 코드


http://brown.ezphp.net/12

mfc사용하지않는 데서cstring이용


http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=651807&ref=651807

unicode TCHAR printf


http://anow.tistory.com/155

아 유니코드로 설정했더니 한글자만 나오는 이유


http://mores.tistory.com/17

유니코드 출력 방법


http://pelican7.egloos.com/viewer/1768951

lpcstr 설명


http://stackoverflow.com/questions/22220659/program-file-x86-when-checked-for-dwfileattributes-returns-a-value-73745-i-ne

FILE_ATTRIBUTE_DIRECTORY를 if로 했을때 모든 폴더가 안나올경우


^ 위에꺼 이유

http://blog.daum.net/nunco00/19

2이유

http://social.msdn.microsoft.com/Forums/en-US/7f5ea6a9-6cfc-48d1-937a-42b7b6ef664b/windows-api-filefolders-attribute


http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx

CreateFile msdn


http://blog.naver.com/PostView.nhn?blogId=sniper209&logNo=70086227841


http://metalkim.tistory.com/320

api파일생성 순서


http://ntcoder.com/bab/2009/03/31/check-directory-or-folder-empty-status/

폴더가 비었는지 안비었는지


저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

win api를 이용한 디렉토리 리스팅  (0) 2014.05.18
api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16
boost access in to all directory  (5) 2014.05.15
boost directory접근  (0) 2014.05.15
Base64 encode  (3) 2014.05.14

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글이 없습니다.
secret

boost를 이용한 모든 디렉토리에 파일만들기


dir_circulation.h


dir_circulation.h


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <boost/filesystem.hpp>
#include <iostream>
#include <string>
#include <boost/filesystem/fstream.hpp>
 
namespace fs = boost::filesystem;
 
class dir_circulation
{
public :
    std::string root;
    std::string filename = "hacked.txt";
    
    void MakeFile(std::string);
    int circulation(std::string);
};
 
int dir_circulation::circulation(std::string path)
{
    fs::path p(root+path);
    if (fs::is_empty(p))
    {
        if (!fs::exists(p / filename))
            dir_circulation::MakeFile(root + path);
        return 0;
    }
 
    else if (fs::exists(p))
    {
        if (fs::is_directory(p))
        {
            if (!fs::exists(p / filename))
                dir_circulation::MakeFile(root + path);
 
            fs::directory_iterator end_itr;
 
            for (fs::directory_iterator dir_itr(p); dir_itr != end_itr; ++dir_itr)
            {
                if (fs::is_directory(dir_itr->status()))
                    dir_circulation::circulation(path+"//"+ dir_itr->path().filename().string());
            }
        }
    }
    return 0;
}
 
void dir_circulation::MakeFile(std::string path)
{
    fs::ofstream f(path+"//"+filename);
    f << "Hacked by layer";
    f.close();
}


main.cpp

main.cpp


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <boost/filesystem.hpp>
#include <iostream>
#include <string>
#include "dir_circulation.h"
 
using namespace std;
class dir_circulation circ;
 
int main()
{
    string empty="";
    circ.root = "E://t//";
    circ.circulation(empty);
 
    cout << "ok";
}
 


저작자 표시 비영리 동일 조건 변경 허락
신고

'공부 > c++' 카테고리의 다른 글

api handle?  (0) 2014.05.16
win api (folder, file)  (0) 2014.05.16
boost access in to all directory  (5) 2014.05.15
boost directory접근  (0) 2014.05.15
Base64 encode  (3) 2014.05.14
배열  (0) 2014.03.24

WRITTEN BY
Jen6
jen6의 개발, 보안 블로그 까끔가다 쓸대 있는걸 올리려고 노력중

받은 트랙백이 없고 , 댓글  5개가 달렸습니다.
  1. http://3dmpengines.tistory.com/1053
  2. http://www.boost.org/doc/libs/1_49_0/libs/filesystem/v3/doc/tutorial.html
  3. http://prettygom.com/entry/boost-path-%EC%82%AC%EC%9A%A9%EB%B2%95
  4. http://blog.daum.net/naivewolf/1979419
  5. http://fmttm.egloos.com/viewer/4791867
secret