1. 목표
multi thread에서 시간을 관리하는 방법을 알아 보겠습니다.
꼭 C++에 만 해당되는 내용은 아닙니다. C library를 사용한다면 발생 합니다.
2. multi thread에서의 시간 함수 사용시 주의해야 할 사항
multi thread 환경에서 gmtime() 함수와 localtime() 함수를 같이 사용하면 시간 값에서 충돌이 발생 합니다. 왜냐하면 내부적으로 gmtime과 localtime는 같은 시간 변수를 공유 하기 때문에 문제가 발생 합니다. 이걸 방지 하기위해서 C Library에서는gtime_r() 과 localtime_r()을 제공 합니다. 이 함수들은 내부적으로 "시간 변수" 서로 유 하지 않습니다.
1) 증명
(1) 코드
#include <iostream>
#include <time.h>
int main()
{
struct tm tstruct; // 기본 사용가능
time_t lt = time(NULL);
std::cout << "gmtime() address : " << gmtime(<) << std::endl;
std::cout << "localtime() addres : " << localtime(<) << std::endl;
std::cout << std::endl;
std::cout << "struct tm 변수addres : " << &tstruct << std::endl;
std::cout << "localtime_r() address : " << localtime_r(<, &tstruct) << std::endl;
std::cout << "gmtime_r() address : " << gmtime_r(<, &tstruct) << std::endl;
return 0;
}
(2) 결과
[root@localhost cpp_test]# ./local_time
gmtime() address : 0x7fe335c23d20
localtime() addres : 0x7fe335c23d20
struct tm 변수addres : 0x7ffcc859dab0
localtime_r() address : 0x7ffcc859dab0
gmtime_r() address : 0x7ffcc859dab0
참조 : http://www.cplusplus.com/reference/ctime/gmtime/ 에서 data races에 설명 되어있습니다.
3. 필요 헤더
#include <time.h>
4. multi thread에서 사용 가능한 시간 함수
1) struct tm *localtime_r(const time_t *timep, struct tm *result);
- localtime에 맞춰 시간 구하는 함수
2) struct tm *gmtime_r(const time_t *timep, struct tm *result);
- UTC에 맞춰 시간을 구하는 함수
5. multi thread에서 증명
1) 시나리오
- 2개의 Thread(thread1, thread2)를 돌립니다.
- thread1에서는 gmtime_r()을 사용하여 localtime_r과의 충돌을 유도 합니다.
- thread2에서는 localtime_r()을 사용하여 gmtime_r과의 충돌을 유도 합니다.
2) 예제 코드
- thread구현시 lambda를 사용 하였습니다. ([C++ 개발자되기] 4. lambda 사용법)
#include <iostreaem>
#include <sys/timeb.h>
#include <time.h>
int main()
{
std::thread thread1(
[](int count)
{
struct tm tstruct; // 기본 사용가능
std::ostringstream oss;
char buf[128];
for (int i = 0; i < count; i++) {
time_t t = time(NULL);
if (nullptr != gmtime_r(&t, &tstruct)) {
strftime(buf, sizeof(buf), "%Y-%m-%d %T", &tstruct);
oss << buf; // 연-월-일-시-분-초
}
}
}, 100000);
std::thread thread2(
[](int count)
{
struct tm tstruct; // 기본 사용가능
std::ostringstream oss;
char buf[128];
for (int i = 0; i < count; i++) {
time_t t = time(NULL);
if (nullptr != localtime_r(&t, &tstruct)) {
strftime(buf, sizeof(buf), "%Y-%m-%d %T", &tstruct);
oss << buf; // 연-월-일-시-분-초
}
std::cout << "B " << oss.str() << std::endl;
oss.str("");
}
}, 100000);
thread1.join();
thread2.join();
return 0;
}
3) 결과
- localtime 시간만이 정확하게 나옴
[root@localhost cpp_test]# date; ./local_time | uniq
2020. 02. 02. (일) 15:28:21 KST
B 2020-02-02 15:28:21
6. 번외
1) multi thread에서 localtime을 사용 한다고하면 어떻게 될 것인가??
- 5번과 동일한 시나리오 사용
#include <iostream>
#include <sstream>
#include <thread>
int main()
{
std::thread thread1(
[](int count)
{
struct tm *tstruct; // 기본 사용가능
std::ostringstream oss;
char buf[128];
for (int i = 0; i < count; i++) {
time_t t = time(NULL);
if (tstruct = gmtime(&t)) {
strftime(buf, sizeof(buf), "%Y-%m-%d %T", tstruct);
oss << buf; // 연-월-일-시-분-초
}
}
}, 10000);
std::thread thread2(
[](int count)
{
struct tm *tstruct; // 기본 사용가능
std::ostringstream oss;
char buf[128];
for (int i = 0; i < count; i++) {
time_t t = time(NULL);
if (tstruct = localtime(&t)) {
strftime(buf, sizeof(buf), "%Y-%m-%d %T", tstruct);
oss << buf; // 연-월-일-시-분-초
}
std::cout << "B : : " <<oss.str() << std::endl;
oss.str("");
}
}, 10000);
thread1.join();
thread2.join();
return 0;
}
2) 예제 코드
3) 결과
- gmtime과 localtime이 섞여서 나옴.
[root@localhost cpp_test]# date; ./local_time | uniq
2020. 02. 02. (일) 15:30:05 KST
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
B : : 2020-02-02 06:30:05
B : : 2020-02-02 15:30:05
7. 결론
- multi thread든 아니든 그냥 안전하게 localtime_r()과 gmtime_r()을 사용 합시다. 코드 한줄만 더 치면 됩니다.
8. 연관 포스트
>>[C++ 관련 모든 글 보기]
'프로그래밍 > 리눅스 프로그래밍' 카테고리의 다른 글
[time] Linux - UTC vs Unix Time vs Local time의 차이 (0) | 2020.04.28 |
---|---|
[tmux] 1. tmux 개념 및 설치 및 설정 변경 ~/.tmux.conf (0) | 2020.04.04 |
[Linux Tip] 리눅스 꿀 Tip 모음 (0) | 2019.11.29 |
잡다한 에러 해결 모음 (0) | 2018.12.10 |
[VIM] 1. VIM 을 이용한 코드 정리 정규 표현식 (0) | 2018.11.22 |