문서 편집 권한이 없습니다. 다음 이유를 확인해주세요: 요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다: 사용자. 문서의 원본을 보거나 복사할 수 있습니다. [[분류:프로그래밍]] [[분류:C++]] 원래 쓰레드 마다 별개의 정보를 기록할 필요가 있는 경우는 그다지 많지 않다만, 필요한 경우가 있다. 예를 들면 공통된 데이터를 가지고 스레드들이 공유하며 별개의 데이터를 생산해야 할 때 필요하다. 다음 코드는 C++에서 스레드마다 별개의 데이터를 가져야 하는 경우를 보여준다. <source lang="C++"> #include <iostream> #include <memory> #include <mutex> #include <optional> class Tokeniser { public: Tokeniser(const char * str, char pattern):m_str(str), m_pattern(pattern) { } std::optional<size_t> Next() { thread_local size_t last_index = -1;//static이 필요없다... while (m_str[++last_index] != '\0') { if (m_str[last_index] == m_pattern) { return std::optional<size_t>(last_index); } } return std::nullopt; } const char* GetStr() const { return m_str; } private: char m_pattern; const char * m_str; }; int main() { Tokeniser tokeniser("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", ' '); std::thread threads[5]; std::mutex m; for (std::thread& thread : threads) { thread = std::move(std::thread([&m, &tokeniser]() { size_t pre = 0; for (auto endindex = tokeniser.Next(); endindex.has_value(); endindex = tokeniser.Next()) { m.lock(); for (size_t i = pre; i < endindex.value(); i++) { std::cout << tokeniser.GetStr()[i]; } m.unlock(); std::cout << std::endl; pre = endindex.value(); } })); } for (std::thread& thread : threads) { thread.join(); } return 0; } </source> 이렇게 스레드마다 별개의 데이터를 가져야 할 때, 외부에서 동적 메모리를 할당하지 않고, 유지할 수 있는 방법을 thread_local 키워드가 제공한다. windows에서는 C++11이 나오기 전에 TLS라 하여 동일한 개념을 지원했다. 사실 이런 경우는 iterator패턴을 쓰면 된다. <source lang="C++"> #include <iostream> #include <memory> #include <mutex> #include <optional> class Tokeniser { public: Tokeniser(const char * str, char pattern):m_str(str), m_pattern(pattern) { } class Token { public: Token(Tokeniser* tokenizer,const std::optional<size_t>& i) :m_tokenizer(tokenizer), lastIndex(i) { if (lastIndex.has_value() == false) return; size_t last_index = lastIndex.value(); while (m_tokenizer->m_str[++last_index] != '\0') { if (m_tokenizer->m_str[last_index] == m_tokenizer->m_pattern) { lastIndex = std::optional<size_t>(last_index); return; } } lastIndex = std::nullopt; } void operator ++() { if (lastIndex.has_value() == false) return; size_t last_index = lastIndex.value(); while (m_tokenizer->m_str[++last_index] != '\0') { if (m_tokenizer->m_str[last_index] == m_tokenizer->m_pattern) { lastIndex = std::optional<size_t>(last_index); return; } } lastIndex= std::nullopt; } bool operator != (const Token & ref) { return ref.lastIndex.has_value() == false && this->lastIndex.has_value() == true; } size_t operator * () { return lastIndex.value(); } std::optional<size_t> lastIndex; Tokeniser * m_tokenizer; }; Token begin() { return Token(this, std::optional<size_t>(-1)); } Token end() { return Token(this, std::nullopt); } const char* GetStr() const { return m_str; } private: char m_pattern; const char * m_str; }; int main() { Tokeniser tokeniser("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", ' '); std::thread threads[5]; std::mutex m; for (std::thread& thread : threads) { thread = std::move(std::thread([&m, &tokeniser]() { size_t pre = 0; for (size_t it :tokeniser) { m.lock(); for (size_t i = pre; i < it; i++) { std::cout << tokeniser.GetStr()[i]; } m.unlock(); std::cout << std::endl; pre = it; } })); } for (std::thread& thread : threads) { thread.join(); } return 0; } </source> Thread local의 사용법 문서로 돌아갑니다.