이것은 한낱 대학생이 교수의 수업을 듣고 작성한 개인저장용 복습 문서입니다.
그렇지만, 물론 지적과 수정은 환영합니다.
POSIX Times
- 시스템의 시간은 Epoch(컴퓨터의 시간이 시작되는 시점) 이후로 초 단위로 유지됩니다.
- Epoch는 1970 년 1 월 1 일 00:00 (자정)으로서, UTC 시간을 기준으로 합니다.
- POSIX는 시스템 시간이 실제 시간 및 날짜와 일치되는 방법을 지정하지 않았습니다.
Time in seconds
#include <time.h>
time_t time(time_t *tloc);
- epoch time으로부터 얼마나 시간이 지났는지
- tloc : output파라미터, NULL이 아니라면, tloc에 저장 (return값과 동일, long타입의 일종)
- 성공시 epoch로부터 지난 초를 리턴, 실패시 (time_t) -1 리턴
- 32비트 시스템에서는 2038년에 이 값이 overflow된다.
#include <time.h>
double difftime(time_t time1, time_t time0);
- time1 - time2 의 시간값 리턴
Displaying date and time
#include <time.h>
struct tm *gmtime(const time_t *timer);
struct tm *localtime(const time_t *timer);
char* asctime(const struct tm *timeptr);
char* ctime(const time_t *clock);
- gmtime() : 파라미터를 주면 UTC 시간에 맞추어 정보를 변환하여 tm구조로 리턴
- localtime() : 파라미터를 주면 현재 지역에 맞도록 해당 정보를 변환하여 tm구조로 리턴
- asctime() : tm구조체를 받아 해당 정보를 string으로 변환해준다.
- ctime() : asctime()과 하는 일을 동일하나, clock 파라미터를 받는다.
- 참고로 asctime, ctime, localtime는 thread-safe하지 못한 함수이다.
- struct tm : 시간에 관한 구조체로서 여기서 연도,월, 등등의 정보를 가져올 수 있다.
• int tm_sec; /* seconds [0,59]*/
• int tm_min; /* minutes [0,59] */
• int tm_hour; /* hours [0,23] */
• int tm_mday; /* day of the months [1,31] */
• int tm_mon; /* months [0, 11] */
• int tm_year; /* years since 1900 */
• int tm_wday; /* days since Sunday [0,6] */
• int tm_yday; /* days since January 1 [0, 365] */
• int tm_isdst; /* flag for daylight-saving time */
struct timeval
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
- epoch로 부터 지난 second와 microsecond를 얻어오는 함수
- struct timeval : tv_sec(second from epoch)과 tv_usec(microsecond from epoch)을 가지는 구조체
- tp : 일종의 output 파라미터.
- tzp : 무조건 NULL값을 가져야함 (역사적인 이유로)
- 성공시 0리턴.
PROGRAM 9.11
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
|
#include <stdio.h>
#include <sys/time.h>
#define MILLION 1000000L
void function_to_time(void);
int main(void) {
long timedif;
struct timeval tpend;
struct timeval tpstart;
if (gettimeofday(&tpstart, NULL)) {
fprintf(stderr, "Failed to get start time\n");
return 1;
}
function_to_time(); /* timed code goes here */
if (gettimeofday(&tpend, NULL)) {
fprintf(stderr, "Failed to get end time\n");
return 1;
}
timedif = MILLION*(tpend.tv_sec - tpstart.tv_sec) +
tpend.tv_usec - tpstart.tv_usec;
printf("The function_to_time took %ld microseconds\n", timedif);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
- function_to_time() 라는 함수가 돌아가는 데에 걸리는 시간을 알 수 있다.
Using real-time clocks
#include <time.h>
int clock_getres(clockid_t clock_id, struct timespec *res);
int clock_gettime(clockid_t clock_id, struct timespec *tp);
int clock_settime(clockid_t clock_id, const struct timespec *tp);
- clock : 'clock resolution'이라고 불리는 일정간 간적으로 증가하는 카운터.
- clock_id에는 보통 CLOCK_REALTIME을 넣는다. (실제 시간)
- struct timespec : time_t tv_sec(seconds)와 long tv_nsec(nanoseconds)를 가진다.
- 성공 시 0을 리턴하고, 실패시 errno을 지정하고 -1을 리턴한다.
Example using real-time clocks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <stdio.h>
#include <time.h>
#define MILLION 1000000L
void function_to_time(void);
int main (void) {
long timedif;
struct timespec tpend, tpstart;
if (clock_gettime(CLOCK_REALTIME, &tpstart) == -1) {
perror("Failed to get starting time");
return 1;
}
function_to_time(); /* timed code goes here */
if (clock_gettime(CLOCK_REALTIME, &tpend) == -1) {
perror("Failed to get ending time");
return 1;
}
timedif = MILLION*(tpend.tv_sec - tpstart.tv_sec) + (tpend.tv_nsec - tpstart.tv_nsec)/1000;
printf("The function_to_time took %ld microseconds\n", timedif);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
Sleep functions
#include <unistd.h>
unsigned sleep(unsigned seconds);
- 프로세스를 일정 시간동안 잠재우는 함수. 인터럽트되어도 깨질 수 있다.
- 보통 0 리턴. 인터럽트되면 보통 남아있는 시간값 리턴.
- 초 단위 수행
#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
- rmtp : 남아있는 시간을 저장하는 아웃풋 파라미터
- 성공시 0을 리턴하고, 실패하면 errno을 재정한 다음 -1을 리턴한다.
- nanos단위 수행
Interval Timer
Timers
- OS에서 타이머를 여러가지 방법으로 제공한다.
- XSI Timer, TMR Timer 등
XSI Interval Timers
- struct itimerval 구조체를 사용.
- timeval it_value; : 한번 돌릴 때 사용할 값
- timeval it_interval; : 반복시킬 때 사용할 값
#include <sys/time.h>
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *restrict value, struct itimerval *restrict ovalue);
- getitimer : timer의 현재 설정값을 value에 넣는다. (value가 일종의 output 파라미터)
- setitimer : 설정된 timer에 value값을 넣는다.
- cf. timer가 끝나면 알람시그널(SIGALRM) 발생
- value : 설정할 타이머값
- value의 it_interval값이 0이 아니면 해당 타이머 종료 후에도 계속 돈다.
- 0이면 기준값 종료후엔 그냥 종료
- value의 it_value까지 0이면 해당 타이머가 그냥 종료된다. (만약 실행중이었다면)
- which : 어떤 종류의 시간으로 넣을 것이냐?
- realtime으로 흘러가길 원하면 ITIMER_REAL
- 프로세스가 running 중인 경우에만 흘러가길 원하면 ITIMER_VIRTUAL
- running 혹은 해당 프로세스를 위한 작업 시에 흘러가길 원하면 ITIMER_PROF
Example of timer
static int setupitimer(void) {
struct itimerval value;
value.it_interval.tv_sec = 2;
value.it_interval.tv_usec = 0;
value.it_value = value.it_interval;
return (setitimer(ITIMER_PROF, &value, NULL));
}
- itimerval 구조체로 구성된 value의 내부 값들을 수정하여 사용한다.
- 그 후 setitimer를 사용하여 timer를 세팅한다.
struct itimerval ovalue, value;
ovalue.it_interval.tv_sec = 0;
ovalue.it_interval.tv_usec = 0;
ovalue.it_value.tv_sec = MILLION;
ovalue.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &ovalue, NULL);
function_to_time();
getitimer(ITIMER_VIRTUAL, &value);
- itimerval 구조체인 ovalue와 value를 선언한다.
- ovlaue의 값을 각각 지정하고
- ITIMER_VIRTUAL에 해당 정보를 준다.
- 그리고 function_to_time();함수 실행 후
- getitimer로 해당 타이머의 시간이 얼마나 흘렀는지 value로 받아준다.
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
|
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
/* ARGSUSED */
static void myhandler(int s) {
char aster = '*';
int errsave;
errsave = errno;
write(STDERR_FILENO, &aster, 1);
errno = errsave;
}
static int setupinterrupt(void) { /* set up myhandler for SIGPROF */
struct sigaction act;
act.sa_handler = myhandler;
act.sa_flags = 0;
return (sigemptyset(&act.sa_mask) || sigaction(SIGPROF, &act, NULL));
}
static int setupitimer(void) { /* set ITIMER_PROF for 2-second intervals */
struct itimerval value;
value.it_interval.tv_sec = 2;
value.it_interval.tv_usec = 0;
value.it_value = value.it_interval;
return (setitimer(ITIMER_PROF, &value, NULL));
}
int main(void) {
if (setupinterrupt()) {
perror("Failed to set up handler for SIGPROF");
return 1;
}
if (setupitimer() == -1) {
perror("Failed to set up the ITIMER_PROF interval timer");
return 1;
}
for ( ; ; ); /* execute rest of main program here */
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
- 우선 setupinterrupt로 signal_handler를 조정해준다.
- handler는 화면에 *을 출력시켜준다.
- 그 후 setupitimer로 itimer를 생성하여 2초마다 signal_handler가 *를 출력하도록 한다.
TMR interval timers
- CLOCK_REALTIME과 같은 작은 클록 및 프로세스는 각 클록에 대해 많은 독립 타이머를 작성할 수 있다.
- itimerspec를 활용하면 된다.
- struct timespec it_interval; (timer의 interval 시간)
- struct timespec it_value; (초기 시간)
- nsec까지 표현이 가능해서 resolution이 좋다고 할 수 있다.
#include <signal.h>
#include <time.h>
int timer_create(clockid_t clock_id, struct sigevent *restrict evp, timer_t *restrict timerid);
- timer 하나를 만든다.
- fork로 상속되지 않는다.
- clock_id : timer가 기반을 둘 clock 선택
- timerid : output 파라미터, timer 생성으로 생성된 timer의 id가 넘어온다.
- evp : 발생시킬 signal을 선택할 수 있도록 하는 구조체.
- evp->sigev_signo : signal num 선택가능 (SIGALARM이 기본값)
- evp->sigev_notify : SIGEV_SIGNAL로 signal이 생기도록 하거나, SIGEV_NONE으로 signal이 안 생기도록 할 수도있다.
- evp에 null을 줄 경우 기본값으로 셋팅된다.
int timer_delete(timer_t timerid)
- timerid를 주어 해당 timer를 삭제한다.
#include
int timer_getoverrun(timer_t timerid);
int timer_gettime(timer_t timerid, struct itimerspec *value);
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue);
- 이전의 gettime과 settime과 같이 활용할 수 있다.
- 해당 timerid에 해당하는 timer에 value값을 주거나, 얻어올 수 있다.
- getoverrun은 timer에서 몇개나 signal을 overrun했는가를 알 수 있는데, 현재 단계에서는 몰라도 된다.
- flag는 옵션정보. 0은 절대시간, 1은 상대시간. 보통 그냥 0 사용.
PROGRAM 9.12
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
|
#include <stdio.h>
#include <time.h>
#define MILLION 1000000L
#define THOUSAND 1000
void function_to_time(void);
int main(void) {
long diftime;
struct itimerspec nvalue, ovalue;
timer_t timeid;
if (timer_create(CLOCK_REALTIME, NULL, &timeid) == -1) {
perror("Failed to create a timer based on CLOCK_REALTIME");
return 1;
}
ovalue.it_interval.tv_sec = 0;
ovalue.it_interval.tv_nsec = 0;
ovalue.it_value.tv_sec = MILLION; /* a large number */
ovalue.it_value.tv_nsec = 0;
if (timer_settime(timeid, 0, &ovalue, NULL) == -1) {
perror("Failed to set interval timer");
return 1;
}
function_to_time(); /* timed code goes here */
if (timer_gettime(timeid, &nvalue) == -1) {
perror("Failed to get interval timer value");
return 1;
}
diftime = MILLION*(ovalue.it_value.tv_sec - nvalue.it_value.tv_sec) +
(ovalue.it_value.tv_nsec - nvalue.it_value.tv_nsec)/THOUSAND;
printf("The function_to_time took %ld microseconds or %f seconds.\n",
diftime, diftime/(double)MILLION);
return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
|
Timer drift
- 타이머가 정기적으로 울리지만, '타이머가 종료' <-> '다시 시작' 사이에 딜레이가 발생할 수 있다.
- 이 딜레이가 커지면서 누적되면, 문제가 발생할 수 있다.
- 따라서 22초마다 울리게 하고 싶으면, 알람시간 T에 대해 [T = current time + 22]보단, [T = T + 22]를 활용하는 것이 좋다.
- 절대시간을 활용하면 이런 문제를 좀 더 깔끔하게 해결할 수 있다.
'💻 CS > 시스템프로그래밍' 카테고리의 다른 글
유닉스 시작하기 (0) | 2020.11.19 |
---|---|
[시스템프로그래밍] POSIX Threads (0) | 2019.12.10 |
[시스템프로그래밍] Signals (0) | 2019.12.06 |
[시스템프로그래밍] UNIX Special Files (0) | 2019.12.01 |
[시스템프로그래밍] Files and Directories (0) | 2019.11.26 |