๐งต ์ค๋ ๋ ๋ก์ปฌ ์ ์ฅ์(TLS) ๊ตฌํํ๊ธฐ: C++ ๊ฐ๋ฐ์๋ฅผ ์ํ ๋ฉํฐ์ค๋ ๋ฉ ๋น๋ฐ ๋ฌด๊ธฐ ๐ ๏ธ

2025๋ 3์ ๊ธฐ์ค ์ต์ C++ ํ์ค์ ๋ฐ์ํ TLS ๊ตฌํ ๊ฐ์ด๋
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ! ์ค๋์ ์ง์ง ๊ฟ์ผ ์ฃผ์ ๋ก ์ฐพ์์์ด์~ ๋ฐ๋ก ์ค๋ ๋ ๋ก์ปฌ ์ ์ฅ์(Thread Local Storage, TLS)์ ๋ํด ํจ๊ป ์์๋ณผ ๊ฑฐ์์! ๐
๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐํ ๋ ๊ฐ๋ "์ ์ด๊ฑฐ ์ด๋ป๊ฒ ํด๊ฒฐํ์ง?" ํ๋ ์๊ฐ ์์์์? ๊ทธ๋ด ๋ TLS๊ฐ ์ง์ง ๊ตฌ์ธ์ฃผ์ฒ๋ผ ๋ฑ์ฅํ๋ค๋๊น์! ใ ใ ใ ํนํ C++ ๊ฐ๋ฐ์๋ผ๋ฉด ์ด ๊ฐ๋ ํ์คํ ์์๋๋ฉด ๋์ค์ ์ง์ง ๋ง์ ๋์์ด ๋๋ต๋๋ค!
์ด ๊ธ์์๋ TLS์ ๊ฐ๋ ๋ถํฐ ์์ํด์ C++์์ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง, ์ค์ ์ฌ์ฉ ์ฌ๋ก๊น์ง ์ฝ๊ณ ์ฌ๋ฐ๊ฒ ์์๋ณผ๊ฒ์. ์ฝ๋ ์์ ๋ ๋ง์ด ์ค๋นํ์ผ๋ ๋ฐ๋ผ์ค์๋ฉด์ ์ค์ตํด๋ณด์ธ์! ๐ช
๐ ๋ชฉ์ฐจ
- ์ค๋ ๋ ๋ก์ปฌ ์ ์ฅ์(TLS)๋?
- ์ TLS๊ฐ ํ์ํ๊ฐ์?
- C++์์ TLS ๊ตฌํ ๋ฐฉ๋ฒ
- TLS ์ฌ์ฉ ์ ์ฃผ์์ฌํญ
- ์ค์ ์์ : TLS๋ฅผ ํ์ฉํ ๋ก๊น ์์คํ
- ์ฑ๋ฅ ์ต์ ํ ํ
- C++20/23์์์ TLS ๊ด๋ จ ๋ณํ
- ๋ง๋ฌด๋ฆฌ ๋ฐ ์ถ๊ฐ ์๋ฃ
1. ์ค๋ ๋ ๋ก์ปฌ ์ ์ฅ์(TLS)๋? ๐ค
์ค๋ ๋ ๋ก์ปฌ ์ ์ฅ์(TLS)๋ ๊ฐ ์ค๋ ๋๊ฐ ์์ ๋ง์ ๋ ๋ฆฝ์ ์ธ ๋ณ์๋ฅผ ๊ฐ์ง ์ ์๊ฒ ํด์ฃผ๋ ๋ฉ์ปค๋์ฆ์ด์์. ์ฝ๊ฒ ๋งํ๋ฉด, ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์คํ๋๋๋ผ๋ ๊ฐ์ ์๊ธฐ๋ง์ '๋น๋ฐ ๊ธ๊ณ '๋ฅผ ๊ฐ๋ ๊ฑฐ์ฃ ! ใ ใ
์ผ๋ฐ ์ ์ญ ๋ณ์๋ ๋ชจ๋ ์ค๋ ๋๊ฐ ๊ณต์ ํ์์์? ๊ทธ๋์ ๋์์ ์ ๊ทผํ๋ฉด ๋ฐ์ดํฐ ๋ ์ด์ค(data race)๊ฐ ๋ฐ์ํ ์ ์์ด์. ๊ทผ๋ฐ TLS๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ ์ค๋ ๋๊ฐ ๊ฐ์ ์ด๋ฆ์ ๋ณ์๋ฅผ ์ฌ์ฉํด๋ ์ค์ ๋ก๋ ๊ฐ์ ๋ค๋ฅธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๋ฌธ์ ๊ฐ ์๋ต๋๋ค! ๐
์ ๊ทธ๋ฆผ์์ ๋ณผ ์ ์๋ฏ์ด, ๊ฐ ์ค๋ ๋๋ ๊ฐ์ ์ด๋ฆ์ ๋ณ์(counter, buffer, isReady)๋ฅผ ๊ฐ์ง๊ณ ์์ง๋ง, ์ค์ ๊ฐ์ ๋ชจ๋ ๋ค๋ฅด์ฃ ! ์ด๊ฒ ๋ฐ๋ก TLS์ ๋ง๋ฒ์ ๋๋ค! โจ
2. ์ TLS๊ฐ ํ์ํ๊ฐ์? ๐ง
๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ค ๋ณด๋ฉด ์ด๋ฐ ์ํฉ ๋ง์ด ๊ฒช์ผ์ จ์ ๊ฑฐ์์:
- ์ ์ญ ๋ณ์ ์ ๊ทผ ์ ๋ฝ(lock)์ด ํ์ํด์ ์ฑ๋ฅ์ด ์ ํ๋จ
- ์ค๋ ๋๋ง๋ค ๋ค๋ฅธ ์ํ๋ฅผ ์ ์งํด์ผ ํ๋๋ฐ ๋งค๋ฒ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ๊ธฐ ๋ฒ๊ฑฐ๋ก์
- ์ค๋ ๋ ์์ ์ฑ(thread safety)์ ๋ณด์ฅํ๊ธฐ ์ํ ์ฝ๋๊ฐ ๋ณต์กํด์ง
- ์ค๋ ๋๋ณ ์์ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ด๋ ค์
์ด๋ฐ ๋ฌธ์ ๋ค์ TLS๊ฐ ๊น๋ํ๊ฒ ํด๊ฒฐํด์ค์! ์๋ฅผ ๋ค์ด, ๋ก๊น ์์คํ ์์ ๊ฐ ์ค๋ ๋๊ฐ ์์ ์ ๋ก๊ทธ ๋ฒํผ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉด ๋ฝ ์์ด๋ ์์ ํ๊ฒ ๋ก๊ทธ๋ฅผ ์์ ์ ์์ฃ . ์์ฆ ๊ฐ์ ๋ฉํฐ์ฝ์ด ์๋์ ์ฑ๋ฅ ํฅ์์ ์ง์ง ํฐ ๋์์ด ๋๋ต๋๋ค! ๐
์ฌ๋ฅ๋ท์์ ํ๋ก๊ทธ๋๋ฐ ๊ฐ์๋ฅผ ์ฐพ์๋ณด๋ฉด, ๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ ๊ด๋ จ ๊ฐ์ข๋ค์ด ๋ง์ด ์์ด์. ํนํ TLS ๊ฐ์ ๊ณ ๊ธ ๊ฐ๋ ์ ๋ฐฐ์ฐ๋ฉด ๋ ํจ์จ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์ฃ !
๐ TLS๊ฐ ํ์ํ ์ค์ ์ฌ๋ก:
- ์น ์๋ฒ์์ ๊ฐ ํด๋ผ์ด์ธํธ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์ค๋ ๋๋ณ ์ปจํ ์คํธ ๊ด๋ฆฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ํ์์ ์ค๋ ๋๋ณ ์ฐ๊ฒฐ ๊ด๋ฆฌ
- ๋๋ค ๋๋ฒ ์์ฑ๊ธฐ์ ์ค๋ ๋๋ณ ์๋(seed) ๊ด๋ฆฌ
- ํ๋กํ์ผ๋ง/๋๋ฒ๊น ๋๊ตฌ์์ ์ค๋ ๋๋ณ ์ ๋ณด ์์ง
- ๋ฉ๋ชจ๋ฆฌ ํ ๋น์(allocator)์ ์ค๋ ๋๋ณ ์บ์ ๊ตฌํ
3. C++์์ TLS ๊ตฌํ ๋ฐฉ๋ฒ ๐ป
C++์์ TLS๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ์ธ ๊ฐ์ง๊ฐ ์์ด์:
3.1 C++11 thread_local ํค์๋ ์ฌ์ฉํ๊ธฐ
C++11๋ถํฐ ๋์ ๋ thread_local ํค์๋๋ ๊ฐ์ฅ ๊ฐ๋จํ๊ณ ํ๋์ ์ธ ๋ฐฉ๋ฒ์ด์์. ์ด ํค์๋๋ก ์ ์ธ๋ ๋ณ์๋ ๊ฐ ์ค๋ ๋๋ง๋ค ๋ ๋ฆฝ์ ์ธ ๋ณต์ฌ๋ณธ์ ๊ฐ๊ฒ ๋ฉ๋๋ค.
// ๊ธฐ๋ณธ์ ์ธ thread_local ์ฌ์ฉ ์์
#include <iostream>
#include <thread>
#include <vector>
thread_local int counter = 0; // ๊ฐ ์ค๋ ๋๋ง๋ค ๋
๋ฆฝ์ ์ธ counter ๋ณ์
void increment_counter(int id) {
// ๊ฐ ์ค๋ ๋๋ ์์ ๋ง์ counter ๊ฐ์ ๊ฐ์ง
counter += id;
std::cout << "Thread " << id << ": counter = " << counter << std::endl;
}
int main() {
std::vector<std::thread> threads;
// 5๊ฐ์ ์ค๋ ๋ ์์ฑ
for (int i = 1; i <= 5; i++) {
threads.emplace_back(increment_counter, i);
}
// ๋ชจ๋ ์ค๋ ๋ ์ข
๋ฃ ๋๊ธฐ
for (auto& t : threads) {
t.join();
}
// ๋ฉ์ธ ์ค๋ ๋์ counter ๊ฐ ์ถ๋ ฅ
std::cout << "Main thread: counter = " << counter << std::endl;
return 0;
}
์ด ์ฝ๋๋ฅผ ์คํํ๋ฉด ๊ฐ ์ค๋ ๋๋ง๋ค ๋ค๋ฅธ counter ๊ฐ์ ๋ณผ ์ ์์ด์. ๋ฉ์ธ ์ค๋ ๋์ counter๋ 0์ด๊ณ , ๋๋จธ์ง ์ค๋ ๋๋ค์ ๊ฐ์ ๋ค๋ฅธ ๊ฐ์ ๊ฐ์ง๊ฒ ๋ฉ๋๋ค. ์ง์ง ์ ๊ธฐํ์ฃ ? ใ ใ
3.2 ํ๋ซํผ๋ณ TLS ๊ตฌํ ๋ฐฉ์
C++11 ์ด์ ์ด๋ ๋ ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ ๊ฒฝ์ฐ, ํ๋ซํผ๋ณ TLS API๋ฅผ ์ฌ์ฉํ ์ ์์ด์:
Windows์์์ TLS ๊ตฌํ
#include <windows.h>
#include <iostream>
// TLS ์ธ๋ฑ์ค ์ ์ธ
DWORD tlsIndex;
void init_tls() {
// TLS ์ธ๋ฑ์ค ํ ๋น
tlsIndex = TlsAlloc();
if (tlsIndex == TLS_OUT_OF_INDEXES) {
std::cerr << "TlsAlloc failed!" << std::endl;
exit(1);
}
}
void cleanup_tls() {
// TLS ์ธ๋ฑ์ค ํด์
TlsFree(tlsIndex);
}
void set_tls_value(int value) {
// TLS ๊ฐ ์ค์
int* pValue = new int(value);
if (!TlsSetValue(tlsIndex, pValue)) {
std::cerr << "TlsSetValue failed!" << std::endl;
delete pValue;
exit(1);
}
}
int get_tls_value() {
// TLS ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
int* pValue = static_cast<int*>(TlsGetValue(tlsIndex));
if (pValue == nullptr) {
return 0;
}
return *pValue;
}
void free_tls_value() {
// TLS ๊ฐ ๋ฉ๋ชจ๋ฆฌ ํด์
int* pValue = static_cast<int*>(TlsGetValue(tlsIndex));
if (pValue != nullptr) {
delete pValue;
TlsSetValue(tlsIndex, nullptr);
}
}
POSIX ์์คํ (Linux, macOS ๋ฑ)์์์ TLS ๊ตฌํ
#include <pthread.h>
#include <iostream>
// TLS ํค ์ ์ธ
pthread_key_t tlsKey;
void destructor(void* value) {
// ์ค๋ ๋ ์ข
๋ฃ ์ ์๋์ผ๋ก ํธ์ถ๋๋ ์๋ฉธ์
delete static_cast<int*>(value);
}
void init_tls() {
// TLS ํค ์์ฑ
if (pthread_key_create(&tlsKey, destructor) != 0) {
std::cerr << "pthread_key_create failed!" << std::endl;
exit(1);
}
}
void cleanup_tls() {
// TLS ํค ์ญ์
pthread_key_delete(tlsKey);
}
void set_tls_value(int value) {
// TLS ๊ฐ ์ค์
int* pValue = new int(value);
if (pthread_setspecific(tlsKey, pValue) != 0) {
std::cerr << "pthread_setspecific failed!" << std::endl;
delete pValue;
exit(1);
}
}
int get_tls_value() {
// TLS ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
int* pValue = static_cast<int*>(pthread_getspecific(tlsKey));
if (pValue == nullptr) {
return 0;
}
return *pValue;
}
์ ์ฝ๋๋ค์ ์ข ๋ณต์กํด ๋ณด์ด์ฃ ? ใ ใ ใ ๊ทธ๋์ ๊ฐ๋ฅํ๋ฉด thread_local ํค์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ํจ์ฌ ํธํด์! ํ์ง๋ง ๋ ๊ฑฐ์ ์ฝ๋๋ ํน์ํ ์ํฉ์์๋ ์ด๋ฐ ๋ฐฉ์๋ ์์๋๋ฉด ์ข๋ต๋๋ค. ๐
3.3 C++17/20์์์ TLS ๊ฐ์ ์ฌํญ
C++17๊ณผ C++20์์๋ TLS ๊ด๋ จ ๋ช ๊ฐ์ง ๊ฐ์ ์ฌํญ์ด ์์ด์:
- โ ์ด๊ธฐํ ์์ ๋ณด์ฅ ๊ฐํ
- โ ์์ธ ์์ ์ฑ ๊ฐ์
- โ ์ฑ๋ฅ ์ต์ ํ
- โ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ปดํฌ๋ํธ์์ ํตํฉ ๊ฐํ
ํนํ C++20์์๋ jthread์ ํจ๊ป ์ฌ์ฉํ ๋ TLS ๋ณ์์ ์๋ช ๊ด๋ฆฌ๊ฐ ๋ ์ฌ์์ก์ด์!
#include <iostream>
#include <thread>
// C++20 ์์
void example_cpp20() {
thread_local struct TLSObject {
int value = 0;
TLSObject() {
std::cout << "TLSObject ์์ฑ๋จ!" << std::endl;
}
~TLSObject() {
std::cout << "TLSObject ์๋ฉธ๋จ! ์ต์ข
๊ฐ: " << value << std::endl;
}
} obj;
std::jthread t1([](int id) {
obj.value = id * 10; // ์ค๋ ๋๋ณ obj ์ธ์คํด์ค์ ์ ๊ทผ
std::cout << "์ค๋ ๋ " << id << ": " << obj.value << std::endl;
}, 1);
std::jthread t2([](int id) {
obj.value = id * 10;
std::cout << "์ค๋ ๋ " << id << ": " << obj.value << std::endl;
}, 2);
// jthread๋ ์๋ฉธ์์์ ์๋์ผ๋ก join() ํธ์ถ
}
์ด ์ฝ๋์์๋ ๊ฐ ์ค๋ ๋๊ฐ ์์ ๋ง์ TLSObject ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๋ฉฐ, ์ค๋ ๋๊ฐ ์ข ๋ฃ๋ ๋ ์๋์ผ๋ก ์๋ฉธ์๊ฐ ํธ์ถ๋ผ์. ๋ํ jthread๋ฅผ ์ฌ์ฉํด์ ์ค๋ ๋ ๊ด๋ฆฌ๊ฐ ๋ ๊ฐํธํด์ก๋ต๋๋ค! ๐
4. TLS ์ฌ์ฉ ์ ์ฃผ์์ฌํญ โ ๏ธ
TLS๋ ๊ฐ๋ ฅํ์ง๋ง, ๋ช ๊ฐ์ง ์ฃผ์ํด์ผ ํ ์ ์ด ์์ด์:
โ ๏ธ TLS ์ฌ์ฉ ์ ์ฃผ์์ฌํญ:
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ฆ๊ฐ: ์ค๋ ๋ ์๊ฐ ๋ง์์๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋น๋กํด์ ์ฆ๊ฐํด์.
- ์ด๊ธฐํ ๋น์ฉ: ๊ฐ ์ค๋ ๋๋ง๋ค TLS ๋ณ์ ์ด๊ธฐํ๊ฐ ๋ฐ์ํ๋ฏ๋ก ๋ณต์กํ ๊ฐ์ฒด์ ๊ฒฝ์ฐ ์ฑ๋ฅ ์ ํ๊ฐ ์์ ์ ์์ด์.
- DLL์์์ ์ฌ์ฉ: Windows์์ DLL ๊ฐ TLS ๊ณต์ ์ ์ฃผ์๊ฐ ํ์ํด์.
- ์ค๋ ๋ ํ ํ๊ฒฝ: ์ค๋ ๋ ์ฌ์ฌ์ฉ ์ TLS ๊ฐ์ด ์์๊ณผ ๋ค๋ฅผ ์ ์์ด์.
- ์ ์ ์ด๊ธฐํ ์์: ์ ์ญ TLS ๋ณ์์ ์ด๊ธฐํ ์์์ ์์กดํ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์.
ํนํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ง์ง ์ค์ํ ํฌ์ธํธ์์! ์๋ฅผ ๋ค์ด, 1MB ํฌ๊ธฐ์ ๋ฒํผ๋ฅผ thread_local๋ก ์ ์ธํ๊ณ 1000๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ๋ฉด ์ฝ 1GB์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ฌ์ฉ๋๋๊น์! ๐ฑ
๊ทธ๋ฆฌ๊ณ TLS ๋ณ์์ ํฌ์ธํฐ๋ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ ๋๋ ํนํ ์ฃผ์ํด์ผ ํด์. ๋ค๋ฅธ ์ค๋ ๋์ ์คํ์ด๋ ์ด๋ฏธ ํด์ ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๋ฉด ์ ๋๊ฑฐ๋ ์!
// ์ํํ TLS ์ฌ์ฉ ์์ - ์ด๋ ๊ฒ ํ์ง ๋ง์ธ์!
thread_local int* dangerous_ptr;
void bad_example() {
int local_var = 42;
dangerous_ptr = &local_var; // ๋ก์ปฌ ๋ณ์ ์ฃผ์๋ฅผ TLS์ ์ ์ฅ (์ํ!)
std::thread t([]{
// ๋ค๋ฅธ ์ค๋ ๋์์ dangerous_ptr ์ฌ์ฉ ์ ์ด๋ฏธ ์๋ฉธ๋ local_var ์ฐธ์กฐ
std::cout << *dangerous_ptr << std::endl; // ๋ฏธ์ ์ ๋์!
});
t.detach(); // ์ค๋ ๋ ๋ถ๋ฆฌ
// ํจ์ ์ข
๋ฃ ์ local_var ์๋ฉธ
}
์ ์ฝ๋๋ ์ ๋ ์ฌ์ฉํ๋ฉด ์ ๋๋ ์์์์! ๋ก์ปฌ ๋ณ์์ ์ฃผ์๋ฅผ TLS์ ์ ์ฅํ๊ณ ๋ค๋ฅธ ์ค๋ ๋์์ ์ฌ์ฉํ๋ฉด ๋ฏธ์ ์ ๋์(undefined behavior)์ด ๋ฐ์ํฉ๋๋ค. ์ด๋ฐ ์ค์ ์กฐ์ฌํ์ธ์! ๐ โโ๏ธ
5. ์ค์ ์์ : TLS๋ฅผ ํ์ฉํ ๋ก๊น ์์คํ ๐
์ด์ ์ค์ ๋ก ์ ์ฉํ ์์ ๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์! TLS๋ฅผ ํ์ฉํ ๊ณ ์ฑ๋ฅ ๋ก๊น ์์คํ ์ด์์. ๊ฐ ์ค๋ ๋๊ฐ ์์ ๋ง์ ๋ก๊ทธ ๋ฒํผ๋ฅผ ๊ฐ์ง๊ณ ์์ด ๋ฝ ์์ด๋ ์์ ํ๊ฒ ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํ ์ ์์ด์.
#include <iostream>
#include <fstream>
#include <thread>
#include <vector>
#include <string>
#include <mutex>
#include <chrono>
class ThreadSafeLogger {
private:
static std::ofstream logFile;
static std::mutex fileMutex;
// ๊ฐ ์ค๋ ๋๋ณ ๋ก๊ทธ ๋ฒํผ
static thread_local std::vector<std::string> logBuffer;
static thread_local int threadId;
// ๋ฒํผ ํฌ๊ธฐ ์ ํ
static constexpr size_t MAX_BUFFER_SIZE = 100;
public:
static void init() {
logFile.open("application.log", std::ios::app);
if (!logFile) {
std::cerr << "๋ก๊ทธ ํ์ผ์ ์ด ์ ์์ต๋๋ค!" << std::endl;
exit(1);
}
}
static void setThreadId(int id) {
threadId = id;
}
static void log(const std::string& message) {
// ํ์ฌ ์๊ฐ ๊ฐ์ ธ์ค๊ธฐ
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
// ๋ก๊ทธ ๋ฉ์์ง ํ์ํ
std::string formattedMsg = "[Thread-" + std::to_string(threadId) + "] ["
+ std::string(std::ctime(&time)).substr(0, 24)
+ "] " + message;
// ์ค๋ ๋ ๋ก์ปฌ ๋ฒํผ์ ์ถ๊ฐ
logBuffer.push_back(formattedMsg);
// ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐจ๋ฉด ํ๋ฌ์
if (logBuffer.size() >= MAX_BUFFER_SIZE) {
flush();
}
}
static void flush() {
if (logBuffer.empty()) {
return;
}
// ํ์ผ ์ฐ๊ธฐ๋ ๋ฝ์ด ํ์ํจ
std::lock_guard<std::mutex> lock(fileMutex);
for (const auto& msg : logBuffer) {
logFile << msg << std::endl;
}
logFile.flush();
logBuffer.clear();
}
static void shutdown() {
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์์ ์ ๋ฒํผ๋ฅผ ํ๋ฌ์ํด์ผ ํจ
flush();
// ๋ฉ์ธ ์ค๋ ๋์์๋ง ํ์ผ ๋ซ๊ธฐ
static std::once_flag closeFlag;
std::call_once(closeFlag, []() {
if (logFile.is_open()) {
logFile.close();
}
});
}
};
// ์ ์ ๋ฉค๋ฒ ์ด๊ธฐํ
std::ofstream ThreadSafeLogger::logFile;
std::mutex ThreadSafeLogger::fileMutex;
thread_local std::vector<std::string> ThreadSafeLogger::logBuffer;
thread_local int ThreadSafeLogger::threadId = 0;
// ์์ปค ์ค๋ ๋ ํจ์
void worker(int id) {
ThreadSafeLogger::setThreadId(id);
for (int i = 0; i < 1000; ++i) {
ThreadSafeLogger::log("์์
" + std::to_string(i) + " ์ฒ๋ฆฌ ์ค...");
// ์ค์ ์์
์๋ฎฌ๋ ์ด์
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
ThreadSafeLogger::log("๋ชจ๋ ์์
์๋ฃ!");
ThreadSafeLogger::flush();
}
int main() {
ThreadSafeLogger::init();
std::vector<std::thread> threads;
const int NUM_THREADS = 5;
// ์ฌ๋ฌ ์ค๋ ๋ ์์ฑ
for (int i = 1; i <= NUM_THREADS; ++i) {
threads.emplace_back(worker, i);
}
// ๋ชจ๋ ์ค๋ ๋ ์ข
๋ฃ ๋๊ธฐ
for (auto& t : threads) {
t.join();
}
ThreadSafeLogger::shutdown();
std::cout << "๋ก๊น
์๋ฃ!" << std::endl;
return 0;
}
์ด ๋ก๊น ์์คํ ์ ์ฅ์ ์ ๋ค์๊ณผ ๊ฐ์์:
- ๊ฐ ์ค๋ ๋๊ฐ ์์ ๋ง์ ๋ก๊ทธ ๋ฒํผ๋ฅผ ๊ฐ์ ธ ๋๋ถ๋ถ์ ๋ก๊น ์์ ์์ ๋ฝ์ด ํ์ ์์
- ๋ฒํผ๊ฐ ์ฐจ๊ฑฐ๋ ๋ช ์์ ์ผ๋ก flush()๋ฅผ ํธ์ถํ ๋๋ง ๋ฝ์ ์ฌ์ฉํด ํ์ผ์ ๊ธฐ๋ก
- ๋ก๊ทธ ๋ฉ์์ง์ ์ค๋ ๋ ID๊ฐ ์๋์ผ๋ก ํฌํจ๋์ด ๋๋ฒ๊น ์ด ์ฌ์
- ์ค๋ ๋ ์ข ๋ฃ ์ ๋จ์ ๋ก๊ทธ๊ฐ ์๋์ผ๋ก ํ๋ฌ์๋จ
์ด๋ฐ ๋ฐฉ์์ ๊ณ ์ฑ๋ฅ ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ง์ด ์ฌ์ฉ๋๋ ํจํด์ด์์. ๋ก๊น ๋๋ฌธ์ ์ฑ๋ฅ์ด ์ ํ๋๋ ๋ฌธ์ ๋ฅผ ํฌ๊ฒ ์ค์ผ ์ ์๊ฑฐ๋ ์! ๐
์ ๋ค์ด์ด๊ทธ๋จ์์ ๋ณผ ์ ์๋ฏ์ด, ๊ฐ ์ค๋ ๋๋ ์์ ๋ง์ ๋ก๊ทธ ๋ฒํผ์ ๋ฉ์์ง๋ฅผ ์๋ค๊ฐ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐจ๊ฑฐ๋ ๋ช ์์ ์ผ๋ก flush()๋ฅผ ํธ์ถํ ๋๋ง ๋ฝ์ ํ๋ํ๊ณ ํ์ผ์ ๊ธฐ๋กํด์. ์ด๋ ๊ฒ ํ๋ฉด ๋ฝ ๊ฒฝํฉ(lock contention)์ ์ต์ํํ ์ ์์ด์! ๐
6. ์ฑ๋ฅ ์ต์ ํ ํ ๐
TLS๋ฅผ ์ฌ์ฉํ ๋ ์ฑ๋ฅ์ ์ต๋ํ ๋์ด์ฌ๋ฆฌ๊ธฐ ์ํ ํ๋ค์ ์์๋ณผ๊ฒ์:
6.1 TLS ๋ณ์ ํฌ๊ธฐ ์ต์ํ
TLS ๋ณ์์ ํฌ๊ธฐ๋ฅผ ์ต์ํํ๋ ๊ฒ์ด ์ค์ํด์. ๊ฐ ์ค๋ ๋๋ง๋ค ๋ณต์ฌ๋ณธ์ด ์์ฑ๋๋ฏ๋ก ํฌ๊ธฐ๊ฐ ํด์๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ์ฆ๊ฐํ๊ณ ์บ์ ํจ์จ์ฑ์ด ๋จ์ด์ ธ์.
// ๋์ ์
thread_local std::array<double, 10000> hugeArray; // ๊ฐ ์ค๋ ๋๋ง๋ค 80KB ์ฌ์ฉ
// ์ข์ ์
thread_local std::unique_ptr<std::array<double, 10000>> lazyArray; // ํ์ํ ๋๋ง ํ ๋น
void use_array() {
if (!lazyArray) {
lazyArray = std::make_unique<std::array<double, 10000>>();
}
// lazyArray ์ฌ์ฉ
}
6.2 ์ด๊ธฐํ ๋น์ฉ ์ค์ด๊ธฐ
TLS ๋ณ์๋ ์ค๋ ๋๊ฐ ์ฒ์ ์ ๊ทผํ ๋ ์ด๊ธฐํ๋ผ์. ๋ณต์กํ ์ด๊ธฐํ ๋ก์ง์ด ์๋ค๋ฉด ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ด์.
// ๋น์ฉ์ด ๋ง์ด ๋๋ ์ด๊ธฐํ
thread_local std::map<std::string, std::vector<int>> expensiveMap = [](){
std::map<std::string, std::vector<int>> m;
// ๋ณต์กํ ์ด๊ธฐํ ๋ก์ง...
return m;
}();
// ๊ฐ์ ๋ ๋ฐฉ๋ฒ: ์ง์ฐ ์ด๊ธฐํ + ์บ์ฑ
std::map<std::string, std::vector<int>>& get_map() {
thread_local std::map<std::string, std::vector<int>>* cache = nullptr;
if (!cache) {
static std::mutex initMutex;
static std::map<std::string, std::vector<int>> masterCopy;
{
std::lock_guard<std::mutex> lock(initMutex);
if (masterCopy.empty()) {
// masterCopy ํ ๋ฒ๋ง ์ด๊ธฐํ
}
}
// ์ค๋ ๋ ๋ก์ปฌ ์บ์์ ๋ณต์ฌ
thread_local std::map<std::string, std::vector<int>> localCopy = masterCopy;
cache = &localCopy;
}
return *cache;
}
6.3 ์บ์ ์ง์ญ์ฑ ํ์ฉ
TLS ๋ณ์๋ ์ค๋ ๋ ์คํ ๊ทผ์ฒ์ ํ ๋น๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ ์บ์ ์ง์ญ์ฑ์ด ์ข์์. ์ด๋ฅผ ํ์ฉํด ์์ฃผ ์ ๊ทผํ๋ ๋ฐ์ดํฐ๋ฅผ TLS์ ์บ์ฑํ๋ฉด ์ฑ๋ฅ์ด ํฅ์๋ ์ ์์ด์.
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ