- 0x0000007b
- 2차세계대전
- 3.20해킹
- 4대강
- 502 error
- 53빌딩
- 7840hs
- 88체육관 수영장
- ABI
- abortive close
- abortive shutdown
- AHCI
- akmods
- ALC1220
- alma linux
- alternatives
- AM4 메인보드
- AMD
- amd 7840hs
- amd 그래픽 게임용
- amd 내장 그래픽 최적화
- anonymous file
- API
- apple.com
- APT
- apt-get
- Armagnac
- Asrock
- ASTALIFT
- audacious player
- Today / Yesterday
- /
- Total
Linux Programmer
gettimeofday를 대체하는 clock_gettime 함수 본문
gettimeofday는 유닉스, 리눅스 시스템 프로그래밍에서 시간을 구할 때 쓰는 함수이다. 마이크로초(백만분의 1초)단위로 구할 수 있는 기능을 가지고 있어서 많이 사용되는 함수이다.
그러나 앞으로 gettimeofday는 지양해야 할 함수가 되었다. 왜냐하면 gettimeofday는 2008년도 유닉스 표준인 SUSv4-2008에서 앞으로 제거될 구식(obsolescent) 함수로 지정했기 때문이다.
물론 하위 호환성을 위해 gettimeofday 함수는 계속 제공될 것이다. 하지만 몇몇 시스템에서는 기본 라이브러리에서 제거되고, 구식 라이브러리를 따로 포함해야 사용할 수 있게 될지도 모르기 때문에 멀티 플랫폼 용으로 개발된다든지 하는 경우라면 gettimeofday를 쓰지 않는 편이 좋다. 참고로 지금까지의 표준안의 행보로 봤을 때 obsolescent 함수로 지정되면 약 10여년의 유예를 거치는 것 같다. 따라서 지금 당장부터 쓰지 말아야 하는 것은 아니다. 물론 기능적인 문제가 생길 수 있는 곳에서는 당장 교체해야 한다. (gettimeofday의 문제점은 아래 monotonic clock의 필요성과 윤초 부분을 보면 되겠다.)
대신에 새로운 함수인 clock_gettime을 사용하면 된다.
gettimeofday는 1988년도에 SVR4에서 표준에 지정되어 20여년을 넘게 사용되던 함수이다. 아직도 수많은 프로그래밍 서적이나 소스 코드의 예제에서 사용되고 있다. 실제로 최근에 개발되던 몇몇 실무 코드 조차 gettimeofday를 사용하고 있는 실정이다.
하지만 가까운 장래에는 removed될 함수이므로 지양하는 편이 좋다. 본인도 가끔 졸린 상태에서 기계적으로 코딩하다보면 gettimeofday를 쓰곤 하는데 지양하도록 주의하는 중이다.
그러면 새로운 함수인 clock_gettime의 프로토 타입부터 살펴보자. 비교를 위해 과거 gettimeofday 도 같이 적어두었다.
#include <time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tp);
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
--------------------------------------------------------------
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
먼저 clock_gettime은 시간 관련 구조체가 struct timespec으로 바뀌었는데 나노초까지 지정할 수 있다. 물론 모든 시스템이 나노초까지 정밀한 시계를 제공하는 것은 아니다. 각 시스템 시계의 정밀도는 clock_getres로 확인할 수 있다.
또한 clock_gettime은 멀티코어 CPU 시대에 걸맞게 쓰레드 안전(thread safety)을 만족하고 있다.
인수로 쓰이는 clockid_t 타입은 시계의 종류를 나타내는 ID로서 POSIX 시스템은 기본적으로 2가지 타입(CLOCK_REALTIME, CLOCK_MONOTONIC)의 시계를 제공한다. 그리고 추가적으로 몇 개의 시계를 더 제공할 수 있다. 아래 표를 보면 몇몇 시계 ID를 정리해두었다. 그러나 실제 시스템에서는 이보다 더 많은 비표준 시계 ID를 제공하기도 한다.
CLOCK_REALTIME | 시스템 전역의 실제 시계(The UNIX Epoch 시간) |
CLOCK_MONOTONIC | 단조 시계 (특정 시점에서 흐른 시간, 대체적으로 부팅후 시간) |
CLOCK_PROCESS_CPUTIME_ID | 프로세스 단위 CPU 사용 시간 |
CLOCK_THREAD_CPUTIME_ID | 쓰레드 단위 CPU 사용 시간 |
여기서 CLOCK_REALTIME을 사용하면 실제 시간을 구하므로 gettimeofday의 기능과 같은 기능을 제공한다.
CLOCK_MONOTONIC은 단조 시계이므로 NTP에 의해서 시스템 시간이 바뀌더라도 영향을 받지 않는다. 따라서 (t1 - t0) 처럼 두 이벤트의 시간차이를 알고자 할 때 유용하다. 과거 gettimeofday의 경우는 NTP나 윤초 관련 기능에 의해서 시스템 시계가 보정될 때 오차가 발생하는 문제가 생길 수 있다. 따라서 최근에는 사용을 지양하도록 하는 기능이다. (이는 logging 관련 부분에서 diff. time의 정밀도가 중요할 때에도 나쁜 영향을 미칠 수 있다.)
이제 현재 시각을 버퍼에 저장하는 간단한 예제 코드를 살펴보자.
main 함수는 생략했으니 적당히 붙여서 코딩하면 될 것이다. 화면에 출력되는 것을 보고 싶다면 printf로 buf 문자열을 출력하면 된다. 다시 말하지만 두 시간의 차(difference)를 구할 경우에는 CLOCK_MONOTONIC을 사용하도록 코딩해야 한다.
#define STR_TIME_FORMAT "%y-%m-%d/%H:%M:%S"
char buf[32];
size_t sz_buf = sizeof(buf);
struct timespec tspec;
struct tm tm_now;
/* 리얼타임 시계로부터 현재 시간을 구한다. */
if (clock_gettime(CLOCK_REALTIME, &tspec) == -1) {
/* 에러 처리*/
}
/* timespec 구조체의 초수 필드(tv_sec)를 tm 구조체로 변환 */
localtime_r((time_t *)&tspec.tv_sec, &tm_now);
/* 문자열로 저장 */
if (strftime(buf, sz_buf, STR_TIME_FORMAT, &tm_now) == 0) {
/* 에러 처리*/
}
참고로 gettimeofday 외에 usleep, getitimer, setitimer도 구식(obsolescent) 함수로 지정되어 나중에는 removed 될 함수이므로 되도록이면 쓰지 않는 편이 좋다. 물론 x86계열의 리눅스에서만 쓸 것이라면 무시하고 써도 된다. 하지만 다른 플랫폼에 포팅할 목적도 있거나 정밀도가 중요한 경우라면 새로운 함수를 사용하는 것을 권장한다.
2024.12.01. 읽어보면 좋은 글 - 철도 시간이 유닉스 시간이 되기까지, 박성범, https://parksb.github.io/article/39.html
'컴퓨터 관련 > 프로그래밍 일반' 카테고리의 다른 글
dart : Invalid UTF8 sequence encountered (0) | 2019.08.24 |
---|---|
TCP의 TIME_WAIT를 없애는 법 (29) | 2013.04.15 |
fork, vfork 그리고 posix_spawn 이야기 (12) | 2013.03.13 |
리눅스에서 XSI와 POSIX 메시지큐 비교 (0) | 2012.10.22 |
TCP/IP 소켓 프로그래밍 주의할 점 (5) | 2012.10.16 |
위키의 TS와 reentrant 관련 오류가 삭제되었다 (0) | 2011.08.01 |
네이버 나눔 글꼴 (개발용 고정폭 폰트) (0) | 2010.11.02 |
소스코드 강조 : SyntaxHighlighter (1) | 2010.03.03 |