'programming'에 해당되는 글 20건

  1. 2016.05.03 template metaprogramming
  2. 2016.04.29 일상 1
  3. 2009.06.02 stack memory allocator
  4. 2009.05.25 ØMQ
  5. 2009.05.21 ABA Problem
  6. 2009.04.09 _set_purecall_handler
  7. 2009.04.06 Memory-Mapped File Copy
  8. 2009.03.31 copy는 실행파일이 아니다(!?)
  9. 2009.03.31 하루 4시간 코딩하기
  10. 2009.03.05 Write in C...
2016. 5. 3. 01:29

template metaprogramming

내가 template metaprogramming을 좋아 하지 않는 이유

런타임 디버깅에 익숙한 개발자들에게는 개발 난이도가 올라가면서, 코드의 가독성의 난해함으로인해 유지 보수의 어려움이 있는데다가, 그런 코드작성에 익숙한 개발자를 뽑기도 힘든데, C#에 익숙해진 나로서는 그 늘어나는 컴파일 타임을 견딜 자신이 없어서 이다.

2016. 4. 29. 02:13

일상 1

최근 시간이 좀 생겨서 처음으로 언리얼엔진을 깔아서 이틀 정도 살펴 볼 기회가 있었음

비주얼 스튜디오 2015를 사용하고 있는데 엔진 소스 받고 인텔리센스 문제 때문에 계속 비주얼 스튜디오가 크래쉬가 나고 있음. 

짜증남...

update2을 받아서 설치하니 더이상 크래쉬가 나지 않음

엔진을 빌드하고 에디터 실행, 횡스크롤 샘플 프로젝트를 기반으로 한 새 프로젝트를 생성 해봄.

블루 프린트 좀 살펴 보다가, 테스트 삼아 프로젝트에 포함된 캐릭터 지우고 우리 프로젝트에서 사용하는 캐릭터 중 하나를 연결 해 볼려고 함.

샘플 캐릭터를 참고해서, 애니메이션 블루프린트 새로 하나 만들어서 이동, 걷기, 점프, A 공격키까지 적용 되는 애님 그래프를 하나 만들어 봄

캐릭터 블루프린트를 애니메이션 블루프린트에서 참조 하는 방법을 몰라 한참 헤맨것을 제외하고는 생각 보다 쉽게 전환이 됨.

C++ 코드 연동을 한번 해 보고 싶어서, Pawn을 상속 받는 MyCharacter 클래스를 하나 만들어 봄.

프로젝트를 만들고 블루프린트만을 사용할 때 프로젝트가 생기지 않고, 새로운 클래스를 생성하는 시점에서 새로운 프로젝트가 생기는 구나.

프로퍼티 설정하는 거 테스트 해보기 위해서, 테스트 코드 몇 개 추가하고 빌드 시도.. 

빌드를 하니 링크 에러가 남...

먼일이지 하는 중 에디터를 닫고 프로젝트를 빌드 하니 빌드가 잘 됨.

다시 에디터를 띄우니까 링크 에러가 남. 

디버그 모드로 실행 해 보니, 에디터에서 디버거를 자꾸 종료를 시킴.

짜증남..

여기까지가 1일차

다음 날 회사 와서, 같이 일하는 프로그래머 한테 위에 문제를 이야기 하고 짜증내면서 에디터 다시 닫고, 빌드 실행시키고, 다시 에디터 띄우고 디버그 모드로 실행하니, 새로운 에디터가 뜸....!!

머지? 순간 당황스러웠음.

뒤에서 이걸 지켜 보던 프로그래머가 한마디 함.

C++로 개발 할 때는 디버그 모드로 실행하면 프로그램이 실행되는 게 당연한건데, 요즘 유니티로만 개발하니까 생기는 착각이라고 함.

아 그렇구나, 바로 납득이 됨.

그리고 바로 짜증이 나서, 바로 에디터랑 프로젝트 닫아 버리고, 지금 까지 쳐다도 안보고 있음.....


2009. 6. 2. 12:01

stack memory allocator

// 이 코드는 구현의 예만을 보여주기 위한 것으로
// 실제 사용하기 위해서는 예외 처리나, 메모리 할당 등의 
// 추가적인 구현이 필요.
#include 
#include 

#define SAFE_FREE(buf) if( buf ){ free(buf); buf = 0; }
#define MEM_PTR		unsigned char*

class stack_allocator
{	
	void	_alloc_buffer(size_t stacksize)
	{
		_free_buffer();
		buffer_ = (MEM_PTR)malloc(stacksize);
		top_ = buffer_;
		bottom_ = top_+stacksize;
	}

	void	_free_buffer()
	{
		SAFE_FREE(buffer_);
	}
public:
	stack_allocator(size_t stacksize = 1024):buffer_(0), top_(0), bottom_(0)
	{
		_alloc_buffer(stacksize);
	}

	void*	alloc(size_t size)
	{
		MEM_PTR ret_ptr = top_;
		top_ = ret_ptr + size;
		if( top_ > bottom_ )
		{	// check overflow
			return 0;	//throw exception;
		}
		return ret_ptr;
	}
	
	friend	void* operator new( size_t size, stack_allocator& mem, int count);
	friend	class scoped_mem_stack;

	MEM_PTR	get_top()
	{
		return top_;
	}
protected:
	void	restore(MEM_PTR ptr)
	{
		top_ = ptr;
	}
private:

	MEM_PTR	buffer_;
	MEM_PTR	top_;
	MEM_PTR	bottom_;
};

void* operator new( size_t size, stack_allocator& allocator, int count = 1)
{
	return allocator.alloc(size*count);
};

class scoped_mem_stack
{
public:
	scoped_mem_stack(stack_allocator& allocator):allocator_(allocator)
	{
		backup_top_ = allocator_.get_top();
	}

	~scoped_mem_stack()
	{
		restore();
	}

	void	restore()
	{
		allocator_.restore(backup_top_);
	}
private:
	stack_allocator& allocator_;
	MEM_PTR			 backup_top_;
};

stack_allocator	g_stack_allocator;

struct test_struct
{
	char	buffer[100];
};

void main()
{
	scoped_mem_stack guard(g_stack_allocator);

	MEM_PTR back_ptr = g_stack_allocator.get_top();
	MEM_PTR back_ptr2 = back_ptr;
	assert(back_ptr == g_stack_allocator.get_top());

	void* test_ptr = new(g_stack_allocator) void*;
	back_ptr +=sizeof(void*);
	assert( back_ptr == g_stack_allocator.get_top());

	test_struct*	test_struct_ptr = new(g_stack_allocator) test_struct;
	back_ptr += sizeof(test_struct);
	assert( back_ptr == g_stack_allocator.get_top());

	test_struct**	test_struct_ptr_ptr = new(g_stack_allocator, 5) test_struct*;	
	back_ptr += sizeof(test_struct*)*5;
	assert( back_ptr == g_stack_allocator.get_top());
	guard.restore();

	assert(back_ptr2 == g_stack_allocator.get_top());
}


scoped_lock idiom 과 구현의 방법이 비슷해서 임의로 scoped_mem_stack 이라는 클래스를 사용해 보았다. 
stack을 사용하는 메모리 풀은 흔하게 볼수 있는 예는 아닐것이다. 

stack의 특성상 반드시 할당  받은 순서대로 해제가 되어야 하는 것은 번거로움은 제외 하고라도, 다중 쓰레딩 환경에서도 문제가  될수 있다.

그러나, 위의 구현 예제와 같이 local functin 내에서 일정크기 이상의 메모리 자원이 필요할때 아주 유용하게 사용될수 있을것으로 기대 되며, 매우 빠르다!!!

특히나, stack의 크기(stack allocator가 아닌)를 넘어가는 메모리 자원이 필요할때(게다가 특정 function내에서만 임시로 사용될때) 임시 메모리 버퍼로서 아주 톡톡한 역할을 해 줄수 있을것으로 기대 된다.
allocator의 크기만 유동적으로 조정이 가능하게 구현해 두면, 그냥 막 불러서 사용하면, 해당 function의 scope가 끝나는 시점에서 자동으로(빠르게!!!) 해제가 되니, 이 얼마나 편리하지 않을수가 있을까?

다중 쓰레드 환경에서는 TSS와 같이 사용하면 된다.
2009. 5. 25. 17:29

ØMQ

ØMQ(Zero Message Queue라고 약자가 아닐까 생각됩니다)

Lightweight messaging framework으로 보입니다.

LGPL 라이선스를 따르는 Opensource이며, C++로 작성이 되어 있어서 매우 빠르다고 합니다.

특징적으로는

1. 초당 4,100,000개정도의 메시지의 처리가 가능하다고 하며
2. broker, directory service등의 몇가지 message model들을 사용하고
3. AIX, FreeBSD, HP-UX, Linux, Mac OS X, OpenBSD, OpenVMS, QNX Neutrino, Solaris and Windows등의 OS을 지원하며
4.  C, C++, Java, Python, .NET/Mono and Fortran 등의 API들을 지원한다고 합니다.

많은 기능들을 생각하면, 다운로드 가능한 소스의 크기가 생각보다 작다는 것에 좀 놀랍습니다.(압축을 풀면, 테스트가능한 바이너리들까지 포함해서, 1.26MB 밖에 안됩니다).

소스를 잠깐 살펴 봤는데, 최근에 본 C++ 라이브러리들에 비해서 코드가 상당히 직관적이어서 보기가 좀 편한 편입니다. (소스 파일 이름을 보고 이런 기능이 있겠구나 하고 보면, 다른 파일을 볼 필요없이 대부분의 구현이 그 파일내에 있습니다. 이런게 직관적인거죠 :) )

얼마전부터 메시지 기반의 서버 솔루션을 생각하고 있었는데, Axum을 포함해서 ØMQ까지 비슷한 솔루션들을 자주 접하게 되네요.
역시나, 병렬프로그래밍에서 메시징기반 솔루션이 대세인가 봅니다.

사이트에 가보면, 10Gb 이너넷상에서 실행한 테스트 결과을 볼수 있는데요.

1byte의 메시지 전송 속도가 28.45 마이크로 세컨드 정도가 나온다고 하는데, 1byte의 메시지는 현실성이 없으므로 별로 의미가 없어 보이고, 512byte의 메시지 전송 속도가 33.08 마이크로 세컨드 정도 나온다고 합니다.

8byte 크기의 메시지를 초당 2.8백만개 정도 처리 한다고 하는데요. 위의 사백만개는 어떤 환경에서 나온 수치인지 궁금하네요.

어쨋든 개인적으로 도움이 많이 되는 참고 자료라고 볼수 있을거 같네요.

코드를 좀더 살펴 보고, 다시 포스팅 해 보도록 하겠습니다.

2009. 5. 21. 18:49

ABA Problem

위키디피아에서의 ABA Problem 설명은 lock free stack구현에서의 문제점을 예제로 들고 있습니다.

 

/* Naive lock-free stack which suffers from ABA problem.*

class Stack {


   volatile Obj* top_ptr;

   // Pops the top object and returns a pointer to it.
   Obj* Pop() {
     while(1) {
       Obj* ret_ptr = top_ptr;

       if (!ret_ptr) return NULL;       
       // ** 실행 구간 1
       Obj* next_ptr = ret_ptr->next;          
       // ** 실행 구간 2
       if (CompareAndSwap(top_ptr, ret_ptr, next_ptr)) { 
         return ret_ptr;
       }
       // The stack has changed, start over.
     }
   }
}; 
언뜻 봐서는 코드상으로는 크게 문제가 없어 보이며, 실제로도 자체 구현상으로는 거의 완벽한 
lock free stack이 구현된것으로 생각됩니다.
(** CompareAndSwap()은 인자 1,2가 같은값일때, 1번인자의 값을 3번 값으로 swap시킵니다. 
 Atomic Operations 이므로 매우 빠릅니다.)
그러나, 아래의 시나리오를 봅시다.
스택이 top->A->B->C 로 초기화되어 있다고 가정했을때,


// --- 1번 Thread 작업 --

// 1번 Thread가 pop을 실행합니다.

 ret = A;
 next = B;

// --- 1번 Thread 작업 중 작업전환 -- 

// --- 2번 Thread 작업 -- 

// 2번 스레드의 pop이 실행됩니다.

 { 
   ret = A;   // 1번 스레드의 pop이 끝까지 실행되지 못했으므로, top은 A입니다
   next = B;
   CompareAndSwap(A, A, B)  // 성공, top은 B가 됩니다.
   return A;
 } // 스택상태는 top -> B -> C 이 됩니다.
 { // 2번 쓰레드가 한번더 pop을 실행합니다.
   ret = B;
   next = C;
   CompareAndSwap(B, B, C)  // 성공, top은 C가 되었습니다.
   return B;
 } // 스택상태는 top -> C 이 됩니다. 
 delete B;  // 2번 쓰레드에서 B값을 삭제 합니다.
 { // 2번 쓰레드에서 아까 위해서 pop된 A를 push합니다.
   A->next = C;
   CompareAndSwap(C, C, A)  // 성공,  top은 A가 됩니다.
 } // 스택상태는 top -> A -> C 이 됩니다. 

// --- 2번 Thread 작업 중 작업전환-- 


// --- 1번 Thread 작업 다시 실행-- CompareExchange(A, A, B); 
 // top과 return값이 모두 A이므로 성공이 됩니다.
 // 그러나 B는 2번 Thread에서 삭제가 되어 있으므로, 이 구간 부터, stack은 잘못된 메모리
 // 를 참조하게 됩니다.
 // 이 상황을 ABA Problem 이라고 합니다.
 
쉽게 일어나지 않을 상황 같지만, 일어나지 않는다는 보장도 없는 상황입니다.
물론 C#이나, Java같이 가비지컬렉션을 사용하는 언어에서는 발생되지 않을 문제이지만, 
C계열에서는 반드시 고려가 되어야 될 문제이기도 합니다. 
당장 생각나는 해법으로는 
1. 그냥 sync를 시키면서, 표준 stack을 사용
2. smart pointer를 사용
 
정도가 될거 같지만, 좀더 고민이 필요한 문제일거 같습니다
 
역시 병렬프로그래밍의 길은 멀고도 험한거 같네요 :)
2009. 4. 9. 19:27

_set_purecall_handler

// _set_purecall_handler.cpp
// compile with: /W1
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>

class CDerived;
class CBase
{
public:
   CBase(CDerived *derived): m_pDerived(derived) {};
   ~CBase();
   virtual void function(void) = 0;

   CDerived * m_pDerived;
};

class CDerived : public CBase
{
public:
   CDerived() : CBase(this) {};   // C4355
   virtual void function(void) {};
};

CBase::~CBase()
{
   m_pDerived -> function();
}

void myPurecallHandler(void)
{
   printf("In _purecall_handler.");
   exit(0);
}

int _tmain(int argc, _TCHAR* argv[])
{
   _set_purecall_handler(myPurecallHandler);
   CDerived myDerived;
}
_set_purecall_handler는 순수 가상함수가 호출이 되었을때 호출할 콜백 함수이다.
프로세스가 종료 될 때 콜백함수를 설정하는 atexit()와 비슷한 유사한 형태라고 할수 있다.
오늘 알게 되어서 부끄럽지만, 클래스의 생성자가 완료되기 전까지는 해당 클래스의 인스턴스는 같은 형식이라고
할수 없다고 한다.
위와 같은 꼴 때리는 코드를 작성할 일은 없지만, CDerived 클래스의 생성자가 CBase클래스에게 자신의 인스턴
스(this)를 넘기는데, 이게 유효한 코드라고 볼 수가 없다는 것이다.
언뜻 보면 문제가 없어 보이는 코드지만 CBase의 소멸자가 호출 될 때 에러가 발생한다.

해당 코드의 m_pDerived의 메모리 구조를 보면 위의 그림과 같은 요상한  구조가 만들어진다는 거다.

2009. 4. 6. 18:55

Memory-Mapped File Copy



 500M 정도의 파일을 복사 했을때,

MFC의 CFile나 fopen/fread/fwrite 보다 20% 이상의 성능 향상을 볼수 있다.

진행상태를 나타내기 위해서 잘라서 읽을려면

CopyMemory 부분만 살짝 손대면 된다.

어차피 IO처리라서 큰 차이가 없을것으로 생각했는데..

생각보다 큰 성능 차이를 보여 준다.

2009. 3. 31. 20:51

copy는 실행파일이 아니다(!?)

최근에 한 삽질중의 하나..

파일 Sync를 마추기 위한 툴을 만들고 있는 중..  툴 내부에서 도스 명령어 copy를 실행할 필요가 있어서,

ShellExcuteEx()를 사용해서 아래와 같이 코드를 작성했다.

SHELLEXECUTEINFO si;
ZeroMemory(&si, sizeof(si));
si.cbSize = sizeof(SHELLEXECUTEINFO);
si.lpFile = _T("copy");
si.lpParameters = _T("c:\temp\*.* d:\temp");
si.lpVerb = _T("open");
si.nShow = SW_SHOW;
ShellExecuteEx(&si);

(생각나는대로 작성했으니, 코드가 컴파일 된다는 보장은 없지만, 의미상 이해는 되리라 생각한다.)

그리고 테스트를 해 보니, 실행이 안된다. 다른 실행파일들은 잘 만 실행되는데, copy만 유독 안된다.

한참 괴로워 하는 중.. 생각난것이 도스 시절 copy는 외부 명령어가 아니고, 내부명령어였던 것이다.

copy로 파일 검색을 해 보니, 역시나 copy.com 이나 copy.exe라는 파일은 없다...

흠 그렇군.. 그럼 윈도우즈에서는 cmd가 도스창이니, cmd를 이용하면 되겠구나 라는 생각에 약간의 삽질 후 아래와 같이 코드를 수정했다.

SHELLEXECUTEINFO si;
ZeroMemory(&si, sizeof(si));
si.cbSize = sizeof(SHELLEXECUTEINFO);
si.lpFile = _T("cmd");
si.lpParameters = _T("/C copy c:\temp\*.* d:\temp");
si.lpVerb = _T("open");
si.nShow = SW_SHOW;
ShellExecuteEx(&si);

잘된다.

당연한건데, 나만 몰랐던건가? 라는 자괴감이 든다... -_-

지나고 나서야 생각나는 건데 이 부분은 CI설정했을때도 비슷한 구문을 많이 접했었던건데..

** 참고로 /C 옵션을 주지 않고 실행하면 해당 명령을 실행한후 커맨드 창이 남아 있다. /C를 주어야 해당 명령 완료후 창이 종료 된다.

2009. 3. 31. 20:12

하루 4시간 코딩하기

매주 목요일에 "병렬프로그래밍"에 대한 스터디를 하고 있다.

같은 회사 직원 한분(이팀장님)과, 퇴사하신분 한분(갑대리님-_-)이 기존에 진행을 하고 있던 스터디에 내가 꼽사리 껴서 진행을 하고 있는데, 공부량이 많지 않아서, 큰 도움은 못되고 있는 실정이다. (좀더 노력이 필요한거 같다. -_-)

그런데, 지난주 스터디를 진행하면서, 이런 저런 이야기들을 하다가, 하루동안 코딩에 집중할수 있는 시간에 대한 이야기를 하게 되었는데, 갑대리님이 외국의 어떤 개발자는 출근을 하면(출근시간 8시30분 정도) 오전 동안만 코딩을 하고, 오후에는 전혀 코딩을 하지 않고, 업무에 필요한 회의나, 기타 잡무들 또는 공부를 한다고 한다.
순수하게 코딩하는 시간을 대충 따지면 4시간정도 된다고 하는데, 업무의 효율성이 좋은거 같다고 한다.

그래서 말이 나온김에, 스터디 하시는 분들끼리 다음 스터디까지 비슷한 방식으로 오전에만 코딩에 집중하고, 오후에는 다른 일들을 해보고, 그 경험담을 다음 스터디때 얘기해 보기로 했다.

금요일은 몇가지 일들 때문에, 시작하지 못하고, 월요일 부터 시작해 보기로 했고, 오늘이 2일차가 되는 날인데, 이틀동안의 경험을 간략하게 정리해 보고자 한다.

참고로 요즘 나는 요즘 6시30분에 일어나, 바로 회사에 출근하면 7시30분정도 되는데, 한시간 정도를 운동하고 나면 8시 30분 부터 자리에 앉아 업무를 시작할수 있다.
그래서 나의 업무 시작시간을 8시 30분 정도로 잡으면, 점심시간인 12시 30분까지 4시간 정도의 시간이 있는데, 오전 10시에 진행하는 회의가 10분 정도 있어서 정확하게 얘기하면 3시간 50분 정도의 시간을 가질수 있다고 생각되는데, 대충 4시간이라고 잡아도 문제는 없으리라 생각된다.

1. 첫쨋날
   - 출근 : 오전 8시 20분
       : 이번주는 지하철을 타고 다니기로 했는데, 시간 분배도 잘 못하고, 평소보다 좀 늦게 출근을 해서 8시 20분경에 회사에 도착했다. 그래서, 아침 운동은 생략...
   - 오전 8시 30분
     : 막상 코딩만 할려고 하니, 어떤 것을 먼저 할지를 10분 정도 멍하게 고민하다가, 서버 관련 코딩 부터 시작하기로 했다. 코딩에 집중이 안되서, 설계 문서를 이것 저것 좀 보다가, 9시 경부터 코딩에 몰입하기 시작..
   - 오전 10시
    : 한참 달리고(?) 있는데 아침 회의 시작 10분 정도 미팅후 담배 하나 피고, 다시 자리에 앉는데 까지 15분 정도 걸린거 같다.
   - 오전 10시 15분
   : 다시 코딩을 시작할려고 하니, 다시 집중이 되지 않는다. 10분 정도를 문서 보고, 코드 보고를 하다가, 진행이 잘 안되서, 멍하게 있기가 싫어서, 동기화 관련 프로젝트를 진행하기로 했다.
   - 오전 10시 30분
  : 동기화 관련 프로젝트는 마침 주말 동안에 구조를 생각해 둔게 있어서, 쉽게 코딩에 몰입을 할수가 있었다. 한참 코딩하고, 테스트하고, 코딩하고, 테스트 하고, 1시간 30분 정도를 집중해서 코딩을 할수가 있었고, 의도했던 대로 잘 진행되고 있었다. 12시쯤 지금까지 진행한 코드를 살펴 봤는데, 이전에 작성했던 코드 보다, 깔끔하게 코드가 만들어 진거 같다는 생각이 들었다. 지난주는 코딩량만 많아서 그런지, 코드 구조가 맘에 안드는 부분이 몇몇 보인다.
   - 오전 12시
  : 남은 30분 동안 기존 코드의 리팩토링을 진행하기로 했다. 30분 정도를 코드 리팩토링 하면 느낀 점은 생각보다 30분이라는 시간이 짧지는 않다는 것이다. 제한된 시간이 있고, 그 시간에 최대한 집중을 할려고 노력하니, 상당히 많은 부분을 수정할수 있었다.
   - 오전 12시 30분 
  : 오늘 코딩은 끝. 점심 먹고 와서, 오전에 진행한 작업들을 보니, 생각보다 많은 량의 업무가 진행이 되었다는 느낌이 들었다.

2. 둘쨋날
   - 출근 : 오전 8시 30분
     : 오늘은 더 늦어 버렸다. 아침에 일어나기가 점점 힘들어 진다. 마음을 좀 다잡을 필요가 있을거 같다. 오늘도 운동 생략.... 제일 경계 해야 될것이 자신과 타협하기 시작하는 건데, 좀 더 빡시게 나를 굴릴 필요가 있을거 같다. 
   - 오전 8시 30분
    : 출근하고 바로 업무 시작. 10분정도 오늘 할일을 생각해 보고, 오전 10시까지는 서버쪽 코딩을 10시 회의 이후는 동기화 관련 프로젝트를 진행하기로 결정
  - 오전 8시 40분
   : 코딩 시작, 왠일인지 코딩에 집중하는데 시간이 걸린다. 아무래도 구조가 확실하게 머리속에 정리가 안되어 있다 보니, 코딩을 진행하기가 좀 힘들다. 테스트만 몇개 만들려고 했는데, 그것도 잘 안된다. 그래서 구조를 먼저 잡기로 결정.. 다이어그램을 몇개 그리면서 전체적인 구조를 잡았다. 오후에 이 내용을 문서로 정리하고, 내일 오전에는 실제 코딩을 할수 있을것으로 기대 한다.
  - 오전 10시
   : 아침 회의가 좀 늦어 졌다. 그래서 잠시 담배 하나 피고 와서, 동기화 관련 프로젝트를 시작. 이부분은 프로젝트가 거의 마무리 단계까지 와 있어서, 코딩하기가 무척이나 편하다. 몇가지 작업리스트를 정리한 이후 바로 코딩 시작
  - 오전 11시10분
   : 10시에 진행하기로 했던 회의가 11시가 좀 넘어서야 진행이 되었다. 할 얘기들도 많이 없어서 5분 정도 얘기하고 담배하나 더 피고, 자리에 와서 다시 업무 시작
  - 오전 12시
   : 오늘 목표로 했던 부분의 작업을 다 끝내버렸다. 어제 오후에 다른 일을 하면서, 이 프로젝트의 이런 저런 구조를 생각하다 보니, 생각보다 진도가 빠르다. 그러면서 느낀 점이, 역시 한번씩 쉬어가는게, 전체를 다시 한번 볼수 있게 되는거 같아서, 좋은거 같다는 생각이 든다.

이틀차의 소감을 간단하게 정리하자면,
1. 4시간이 결코 짧지 않은 시간이 아니다.
2. 시간을 정해 두니, 최대한 업무의 집중도를 높히고, 효율적으로 하기 위해서 노력하게 된다.
3. 매일 정신 없이 코딩만 하다가 한발 떨어져 있는 시간이 있다 보니, 전체적인 부분이 훨씬 더 잘 보이게 된다는 점

정도 이다.

아직은 오후 시간에 공부는 하지 못하고 있지만, 시간 관리를 좀더 효율적으로 해야 되겠다는 생각은 들지만, 현재까지는 기대 했던 바 보다는 효과가 있는 거 같다. 
2009. 3. 5. 09:04

Write in C...