Awesome!
http://www.html5rocks.com/
http://www.chromeexperiments.com/
Friday, July 2, 2010
Thursday, July 1, 2010
Google Protocol Buffer 구글의 프로토콜 버퍼
Sometimes when we make data structure and use it for file i/o or network, writing manipulating functions is bothersome. Moreover it's a kind of stress when we have to use it over different environment or implementation. People tried to solve this matter for a long time(Maybe you've heard about XDR before). By the way, Google also faced the same and they were using what so called Google Protocol Buffer. It generates classes to manipulate our data structure expressed with .proto file for c++, python and java.
가끔식 특정 데이터 포맷 만들어 파일에 읽고 쓰거나 네트웍으로 전송할 일이 있을 때 이를 조작하는 함수들을 구현하고 테스트 하는 부분이 성가실 때가 있다. 특히 다른 환경(OS, 서버)이나 구현(언어)에서 동일하게 동작하는지 체크하는 과정은 시간을 잡아먹는다. 그래서 XDR같은 걸로 해결해 보려는 시도가 이전에 있었는데, 알고보니 구글에서도 비슷한 고민을 한거 같다. 얘네들은 구글 프로토콜 버퍼를 사용하는데, .proto 파일로 데이터 구조를 만들고 protoc로 컴파일 하면 c++, 파이썬, 자바로 관련 조작함수나 클래스를 생성해준다. 일종의 코드 제네레이터처럼.
package contacts;
message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
}
This is a simple .proto file. We can compile this with protoc to generate code. Let me try to get a c++ code to manipulate this data format.
간단한 .proto 파일인데, protoc로 컴파일 할 수 있다. C++코드를 만들어보자.
> protoc contact.proto --cpp_out=.
> ls
contact.pb contact.pb.cc contact.pb.h contact.proto
Functions are defined in the header file above and you can also check it at the site. Ok. Now it's the time to use it.
조작함수는 구글 사이트나 contact.pb.h 헤더 파일을 보면 된다. 자, 그럼 한번 써볼까.
#include <iostream>
#include <fstream>
#include "contact.pb.h"
using namespace std;
static const string datafile = "contact.pb";
void pbWrite(int id, string name, string email)
{
Person person;
person.set_id(id);
person.set_name(name);
person.set_email(email);
fstream out(datafile.c_str(), ios::out|ios::binary|ios::trunc);
person.SerializeToOstream(&out);
out.close();
}
int pbRead(Person &p)
{
fstream in(datafile.c_str(), ios::in|ios::binary);
if(!p.ParseFromIstream(&in)) {
fprintf(stderr, "ERROR : Read Person from input stream\n");
return -1;
}
cout << p.DebugString();
/*
cout << "id : " << p.id() << endl;
cout << "name : " << p.name() << endl;
cout << "email : " << p.email() << endl;
*/
in.close();
}
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
//pbWrite(12345, "Dustin Hyun", "dongseok.hyun@emailaddress.com");
Person p;
(void) pbRead(p);
return 0;
}
For version check, you should use macro GOOGLE_PROTOBUF_VERIFY_VERSION. Each member has get/set functions(see the code above). And you can serialize the data with SerializeToOstream() and parse from the file or stream with ParseFromIstream(). So cool and easy. This also works on the other implementation using python or java exactly the same way. It also support convenient functions like DebugString().
구글의 프로토콜 버퍼 버전 체크를 위해 GOOGLE_PROTOBUF_VERIFY_VERSION 매크로를 사용하고, 각 멤버들은 get/set 함수들이 있어 접근할 수 있다. 중요한것은,. 이런 데이터를 SerializeToOstream(), ParseFromIstream() 함수로 파일에 저장하거나 불러올 수 있고, 네트웍상에도 전달할 수 있다는 것. 겁나 편할 뿐 아니라 파이썬, 자바등 다른 언어로 구현된 코드들과도 호환되니 좋을 수밖에. C++로 서버를 구현하고 파이썬 qt로 짠 어플리케이션 클라이언트로 받아야 하는 상황이라면 완전 편하게 사용할 수 있다. DebugString() 같은 편리한 함수도 만들어주니 써보자 ^^;
Ps. don't forget to write -pthread 컴파일시 인스톨한 라이브러리 경로 넣어주는 거 잊지 말자.
Wednesday, April 7, 2010
Time Conversion
- Get struct timeval
gettimeofday() - Get struct timespec
clock_gettime() - Time string -> struct tm
strptime() - struct tm -> time string
strftime() - tm -> unix time time_t
mktime() - Others.
Refer time.h
(asctime() , clock() , difftime() , gmtime() , localtime() , mktime() , strftime() , strptime() , time() , utime())
Tuesday, February 16, 2010
Function Object
In C++, we normally make class instance and call a method of the instance. However, there's a way to call class instance itself as a function like below.
1 #include <iostream>
2 #include <functional>
3
4 using namespace std;
5
6 class Sample
7 {
8 public:
9 int operator() (int a, int b) const {
10 return a + b;
11 }
12 };
13
14 int main()
15 {
16 Sample s;
17 cout << s(1, 2) << endl;
18 return 0;
19 }
You can set input arguments information and return type like line 9 above. Function object is processed as an inline function, so it's fast than normal function call. And it is also useful when you want to set a status related to a certain function cause it's class so it can keep a value as a member.
1 #include <iostream>
2 #include <functional>
3
4 using namespace std;
5
6 class Sample
7 {
8 public:
9 int operator() (int a, int b) const {
10 return a + b;
11 }
12 };
13
14 int main()
15 {
16 Sample s;
17 cout << s(1, 2) << endl;
18 return 0;
19 }
You can set input arguments information and return type like line 9 above. Function object is processed as an inline function, so it's fast than normal function call. And it is also useful when you want to set a status related to a certain function cause it's class so it can keep a value as a member.
Tuesday, January 19, 2010
What right people are heading for in this generation, 'Open'
As time goes by, the world offers more things to see, to know and to feel. If we are right people for this generation, we can feel that the world is going to that trend, 'sharing more and more'.
The meaning of Open posted on Google blog tells exactly what I was heading for(Korean version).
The meaning of Open posted on Google blog tells exactly what I was heading for(Korean version).
Monday, December 28, 2009
한국의 S/W 품질이 낮은 이유
나는 한국의 소프트웨어 품질이 낮다고 생각한다. 건축가가 자신이 설계한 건물에서는 못잔다는 말처럼 직업이 프로그래머이니까 그렇게 느낄 수도 있겠다고 생각할지 모르겠으나, 시간이 지나면 지날 수록 이러한 생각이 확고해 지기만 할 뿐이다.
소프트웨어 품질이 낮다고 동의하는 대부분의 사람들이 개발자의 수준을 먼저 얘기하곤 한다. 심지어 개발자들도 스스로의 수준을 얘기하는 경우가 더러 있다. 하지만, 이건 아니다. 수압이 낮아서 물이 안나오는 데 애꿋은 수도꼭지 탓만 하는 것과 비슷하다.
소프트웨어 품질이 낮다고 동의하는 대부분의 사람들이 개발자의 수준을 먼저 얘기하곤 한다. 심지어 개발자들도 스스로의 수준을 얘기하는 경우가 더러 있다. 하지만, 이건 아니다. 수압이 낮아서 물이 안나오는 데 애꿋은 수도꼭지 탓만 하는 것과 비슷하다.
한국의 소프트웨어 품질이 낮은 이유는 프로그래머의 수준보다는 프로그래머의 의견이 무시되는 개발속도/기능 위주의 개발 환경 때문이다.
프로그램 개발에 관련해 여러사람들과 얘기하다보면 항상하는 얘기가 있다. 어느정도 규모나 완성도를 요구하는 소프트웨어의 개발은 고층건물을 짓는 것과 비슷하다는 얘기다. 단층 주택은 별 고민 없이 뚝딱뚝딱 지을 수 있다. 하지만 100층짜리 건물은 얘기가 다르다. 지반 공사 부터 시작해서 하중 계산, 고층에서의 진동, 내장재의 물리적 특성, 전기 분배, 상하수 배관 시설, 낸난방 및 공조 등의 각 부분에서 물리, 전기, 인체공학 등등의 여러 기술이 복합적으로 사용되어 건물이 완성된다. 프로그램도 마찬가지다. 조엘 온 소프트웨어에는 웹페이지에서 간단한 파일을 업로드 하는 페이지를 예로들고 있다. 수 Kb의 파일을 업로드하는 코드는 10분이면 완성이다. 하지만 Gb라면 어떨까. 파일 업로드 상태를 모니터하는 쓰레드와 서버와 주기적으로 통신하여 상태를 확인하는 코드, 업로드 중에 발생하는 여러 상황에 대한 고려, 업로드 실패시 전송된 부분에 대한 후처리 등 생각할 일이 많다.
하지만 이를 인식한 개발자의 의견이 반영되는 경우는 매우 드물다. 일반적으로는 그냥 업로드 파일의 크기를 수 Mb로 제한하고 대신 다른 다양한 기능을 더 추가하는 방향으로 진행된다. 기능적인 완성도를 추구하는 개발보다는 여러 가지 기능들을 빠른 시일에 화려한 UI와 개발하는 방향으로 진행된다. 굳이 일일이 예를들지 않아도 우리식(?)으로 개발된 프로그램들을 보면 대부분 이런 식이다.
A라는 거대 고객이 X라는 프로그램을 만들어 달란다. B사는 요구하는 기능을 충실히 구현하고 에러가 발생하지 않도록 많은 상황을 고려하여 신뢰성있는 소프트웨어를 개발하는데 집중한다. C사는 B사의 소프트웨어 보다 더 많은 기능을 넣고 화려한 UI로 장식한다. 고객 입장에서 최종 제품을 테스트 해보니 둘다 원하는 기능이 동작하는데 C사는 더 많은 기능을 제공하면서 더 이쁘다. 그래서 C사를 선택한다. 나중에 고객은 미처 예상하지 못했던 오류를 C사의 제품에서 발견한다. B사는 이러한 경우까지 고려했다고 처음에 설명했지만 고객은 오류를 직접 당하기 전까지는 이해하지 못한다. 결국 이런식의 제품 개발이 반복되어 B사도 다기능의 화려한 외양의 소프트웨어 개발에 매진하게 된다.
Friday, December 25, 2009
Brief on Signal
Review SIGNAL
Signal can be used to control process. SIGKILL, SIGSTOP, SIGINT are well known types of signal. No process can mask SIGKILL and SIGSTOP.
In a program, you can register signal handler function so that when a specific signal is sent to a process it can invoke registered signal handler function.
And also you can block in a certain part of the code to wait signal.
In multi-thread program, we can set signal mask so that only specified thread can handle the signal.
* How to register signal handler.
Though we've used the function signal() before, it's ANSI compatible one but not a standard. We can use sigaction() in the standard.
sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
If handler is registered with the function above, handler will be called when the signal occurs.
We use struct sigaction structure to register handler, to set mask, flags.
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); // kind of advanced
// used with sigfillset(), sigemptyset(), sigaddset(), sigdelset()
sigset_t sa_mask;
int sa_flags; // option flags like
/*
SA_NOCLDSTOP, // child의 중지시 SIGCHLD 안받음
SA_ONESHOT/SA_RESETHAND : 일회용 핸들러
SA_NOMASK, SA_NODEFFER : 같은 시그널 발생을 block하지 않음
SA_SIGINFO : 핸들러로 sa_sigaction을 사용
*/
void (*sa_restorer)(void);
};
Sample code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
void usr_handler(int signum);
int main()
{
struct sigaction sa_usr1;
struct sigaction sa_usr2;
memset(&sa_usr1, 0, sizeof(struct sigaction));
sa_usr1.sa_handler = usr_handler;
sa_usr1.sa_flags = SA_NODEFER;
sigfillset(&sa_usr1.sa_mask);
memset(&sa_usr2, 0, sizeof(struct sigaction));
sa_usr2.sa_handler = usr_handler;
sa_usr2.sa_flags = SA_NODEFER;
sigemptyset(&sa_usr2.sa_mask);
sigaction(SIGUSR1, &sa_usr1, NULL);
sigaction(SIGUSR2, &sa_usr2, NULL);
printf("SIGUSR1, SIGUSR2 Registered!\n");
for (;;)
{
pause();
}
return EXIT_SUCCESS;
}
void usr_handler(int signum)
{
int i;
for (i = 0; i < 5; i++)
{
printf("[%d]Caught signal. will sleep 1 sec : SIGUSR%d\n"
,i , (signum == SIGUSR1) ? 1 : 2);
sleep(1);
}
}
* How to block signal in a process
sigprocmask() offers signal blocking.
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
If oldset is not NULL, current signal mask will be copied into oldset.
* How to handle signal in multi-thread program.
As a default, if program receive signal, all of its thread receive the signal and it will make,. a chaos and program will halt. Generally, people set signal mask so that signal can be handled by specific thread.
Like sigprocmask, threre is pthread_sigmask(). If it's called in main(), all thread created after will have that signal mask. It it's called in a certain thread, only that thread will have that mask. In this way, we can specify which thread will receive signal.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#define THREADNUM 5
#define LIFETIME 10
struct s_thread_ctx
{
pthread_t tid;
int index;
}ctx[THREADNUM];
void sig_handler(int);
void *worker(void *);
int main()
{
void *res;
int i;
sigset_t sigmask, sigmask_old;
sigfillset(&sigmask);
printf("[MAIN] Masking all signals\n");
pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask_old);
for (i = 0; i < THREADNUM; i++)
{
ctx[i].index = i;
pthread_create(&ctx[i].tid, NULL, worker, (void *)&ctx[i]);
printf("[MAIN] Create %dth thread\n", i);
}
printf("[MAIN] Joining threads\n");
for (i = 0; i < THREADNUM; i++)
{
pthread_join(ctx[i].tid, &res);
}
return 0;
}
void *worker(void *arg)
{
int i;
sigset_t sigmask;
struct s_thread_ctx *ctx;
struct sigaction sa;
ctx = (struct s_thread_ctx *)arg;
sigfillset(&sigmask);
sigdelset(&sigmask, SIGINT);
sa.sa_handler = sig_handler;
sigfillset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
#ifdef HANDLER_THREAD
/* only last thread will catch SIGINT */
if (ctx->index == (THREADNUM - 1))
{
pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
}
#endif
/* Just waiting for LIFETIME seconds */
for (i = 0; i < LIFETIME; i++)
sleep(1);
return arg;
}
void sig_handler(int signum)
{
if (signum == SIGINT)
{
printf("[HANDLER] I've got SIGINT\n");
}
return;
}
* Handling signal and waiting signal.
If handler is registered, it would be called when specified signal is sent. And we can also wait until the signal arrives.
int sigsuspend(const sigset_t *mask);
Function sigsuspend will block the program until specified signals in mask arrive.
#include <signal.h>
#include <stdio.h>
#include <string.h>
void handler(int signal)
{
printf("[Handler] Signal handled\n");
return;
}
int main()
{
int sig;
sigset_t set;
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &sa, NULL);
sigfillset(&set);
sigdelset(&set, SIGUSR1);
sig = sigsuspend(&set);
printf("SIGUSR1 arrived\n");
return 0;
}
* Signal and process
If a signal is sent to a certain process, it's also sent to all of its child as long as they have same process group id. That means, if a child become a process group leader, signal will not be propagated to it any more.
cf. session = process groups and processes, process group = processes, if pid == pgid, it's process group leader.
related functions : setpid, setpgid, setpgrp, getsid, setsid
> kill -SIGUSR1 -1234 # to send SIGUSR1 signal to all processes which have pgid as 1234
Signal can be used to control process. SIGKILL, SIGSTOP, SIGINT are well known types of signal. No process can mask SIGKILL and SIGSTOP.
In a program, you can register signal handler function so that when a specific signal is sent to a process it can invoke registered signal handler function.
And also you can block in a certain part of the code to wait signal.
In multi-thread program, we can set signal mask so that only specified thread can handle the signal.
* How to register signal handler.
Though we've used the function signal() before, it's ANSI compatible one but not a standard. We can use sigaction() in the standard.
sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
If handler is registered with the function above, handler will be called when the signal occurs.
We use struct sigaction structure to register handler, to set mask, flags.
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); // kind of advanced
// used with sigfillset(), sigemptyset(), sigaddset(), sigdelset()
sigset_t sa_mask;
int sa_flags; // option flags like
/*
SA_NOCLDSTOP, // child의 중지시 SIGCHLD 안받음
SA_ONESHOT/SA_RESETHAND : 일회용 핸들러
SA_NOMASK, SA_NODEFFER : 같은 시그널 발생을 block하지 않음
SA_SIGINFO : 핸들러로 sa_sigaction을 사용
*/
void (*sa_restorer)(void);
};
Sample code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
void usr_handler(int signum);
int main()
{
struct sigaction sa_usr1;
struct sigaction sa_usr2;
memset(&sa_usr1, 0, sizeof(struct sigaction));
sa_usr1.sa_handler = usr_handler;
sa_usr1.sa_flags = SA_NODEFER;
sigfillset(&sa_usr1.sa_mask);
memset(&sa_usr2, 0, sizeof(struct sigaction));
sa_usr2.sa_handler = usr_handler;
sa_usr2.sa_flags = SA_NODEFER;
sigemptyset(&sa_usr2.sa_mask);
sigaction(SIGUSR1, &sa_usr1, NULL);
sigaction(SIGUSR2, &sa_usr2, NULL);
printf("SIGUSR1, SIGUSR2 Registered!\n");
for (;;)
{
pause();
}
return EXIT_SUCCESS;
}
void usr_handler(int signum)
{
int i;
for (i = 0; i < 5; i++)
{
printf("[%d]Caught signal. will sleep 1 sec : SIGUSR%d\n"
,i , (signum == SIGUSR1) ? 1 : 2);
sleep(1);
}
}
* How to block signal in a process
sigprocmask() offers signal blocking.
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
If oldset is not NULL, current signal mask will be copied into oldset.
* How to handle signal in multi-thread program.
As a default, if program receive signal, all of its thread receive the signal and it will make,. a chaos and program will halt. Generally, people set signal mask so that signal can be handled by specific thread.
Like sigprocmask, threre is pthread_sigmask(). If it's called in main(), all thread created after will have that signal mask. It it's called in a certain thread, only that thread will have that mask. In this way, we can specify which thread will receive signal.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#define THREADNUM 5
#define LIFETIME 10
struct s_thread_ctx
{
pthread_t tid;
int index;
}ctx[THREADNUM];
void sig_handler(int);
void *worker(void *);
int main()
{
void *res;
int i;
sigset_t sigmask, sigmask_old;
sigfillset(&sigmask);
printf("[MAIN] Masking all signals\n");
pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask_old);
for (i = 0; i < THREADNUM; i++)
{
ctx[i].index = i;
pthread_create(&ctx[i].tid, NULL, worker, (void *)&ctx[i]);
printf("[MAIN] Create %dth thread\n", i);
}
printf("[MAIN] Joining threads\n");
for (i = 0; i < THREADNUM; i++)
{
pthread_join(ctx[i].tid, &res);
}
return 0;
}
void *worker(void *arg)
{
int i;
sigset_t sigmask;
struct s_thread_ctx *ctx;
struct sigaction sa;
ctx = (struct s_thread_ctx *)arg;
sigfillset(&sigmask);
sigdelset(&sigmask, SIGINT);
sa.sa_handler = sig_handler;
sigfillset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
#ifdef HANDLER_THREAD
/* only last thread will catch SIGINT */
if (ctx->index == (THREADNUM - 1))
{
pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
}
#endif
/* Just waiting for LIFETIME seconds */
for (i = 0; i < LIFETIME; i++)
sleep(1);
return arg;
}
void sig_handler(int signum)
{
if (signum == SIGINT)
{
printf("[HANDLER] I've got SIGINT\n");
}
return;
}
* Handling signal and waiting signal.
If handler is registered, it would be called when specified signal is sent. And we can also wait until the signal arrives.
int sigsuspend(const sigset_t *mask);
Function sigsuspend will block the program until specified signals in mask arrive.
#include <signal.h>
#include <stdio.h>
#include <string.h>
void handler(int signal)
{
printf("[Handler] Signal handled\n");
return;
}
int main()
{
int sig;
sigset_t set;
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &sa, NULL);
sigfillset(&set);
sigdelset(&set, SIGUSR1);
sig = sigsuspend(&set);
printf("SIGUSR1 arrived\n");
return 0;
}
* Signal and process
If a signal is sent to a certain process, it's also sent to all of its child as long as they have same process group id. That means, if a child become a process group leader, signal will not be propagated to it any more.
cf. session = process groups and processes, process group = processes, if pid == pgid, it's process group leader.
related functions : setpid, setpgid, setpgrp, getsid, setsid
> kill -SIGUSR1 -1234 # to send SIGUSR1 signal to all processes which have pgid as 1234
Subscribe to:
Posts (Atom)