ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TLS(Thread Local Storage)
    C++/C++ 멀티스레드 2022. 11. 8. 20:47
    728x90

    안녕하세요.

    오늘은 Thread Local Storage에 대해서 알아보겠습니다.

     


    개념

    게임을 만드는 예를 들어볼게요. 멀티스레드 환경에서 스레드들은 DB관리도 하고, 클라이언트 세션을 처리하기도 하고, 게임로직을 처리하기도 하는 등 다양한 작업을 처리하게 됩니다.

     

    그런데, 이 스레드들은 우리가 생각하는 것처럼 이상적으로 동작하지 않습니다. 우리는 스레드가 공평하게 여러 작업에 투입되길 바라는데 현실은 한, 두개의 작업에 많은 스레드가 몰리게 됩니다.

     

    멀티스레드 프로그래밍의 이상과 현실이라고 유명한 사진이 있습니다.

    멀티스레드 이론과 현실

    여튼 이렇게 하나의 작업에 여러 스레드가 몰리게 되면 비효율적인 상황이 발생합니다. Lock때문인데요.

    멀티스레드 환경에서는 특정 작업을 처리할 때 Lock을 걸고 작업을 하는 경우가 많습니다. Heap영역이나, Data영역같은 공통영역에 대해서 작업을 할 때 하나의 스레드가 특정 데이터에 대해 작업하는 동안에, 다른 스레드가 접근해서 결과가 이상해지는 상황을 방지하기 위해서입니다. 이러한 특성 때문에 스레드는 고유한 개별적인 전역변수나 정적변수를 사용하기가 어렵습니다.

     

    이렇게 Lock을 걸고 작업하기 때문에, 스레드가 여러개라고 하더라도, 동시에 하나의 작업밖에 수행하지 못하는 처참한 결과가 나타납니다.

     

    TLS는 이러한 문제점을 해결하기 위해서 등장하는 개념 중 하나입니다.

     

    스레드가 개별적으로 고유하게 사용할 수 있는 전역변수, 정적변수를 위한 공간을 마련해주는 개념입니다.

    TLS영역을 공통영역에서 가져올 동안만 Lock을 걸고, 이후에는 Lock을 해제하기 때문에

    사용하려는 TLS가 겹치지 않는다면 다른 스레드들은 공통영역의 메모리에 접근할 수 있습니다.

     

     

    Stack과의 차이점

    스레드는 개별적인 stack을 갖기에, stack을 사용하면 되지 않을까 싶지만, stack은 임시변수, 지역변수들을 위한 공간이기에 전역, 정적변수를 담을수는 없습니다.

     


    예제

    스레드는 시스템에서 자동으로 ID를 할당받습니다. 하지만, 이 ID는 조금 복잡합니다. 숫자가 크기도 하고, 연속적이지 않습니다. 그래서 우리는 TLS를 이용해서 사용자가 직접 threadID를 할당할겁니다.

     

    TLS변수를 사용하기 위해서는 일반적인 자료형 앞에 thread_local 이라는 키워드를 붙여주면 됩니다.

     

    #include "pch.h"
    #include "CorePch.h"
    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <Windows.h>
    #include <future>
    
    //TLS공간에 변수 선언 방법
    //변수를 하나만 선언하지만, 각각의 스레드는 자신만의 TLS를 갖게 된다.
    thread_local int LThreadId = 0;
    
    void ThreadMain(int threadId)
    {
    	LThreadId = threadId;
    
    	while (true)
    	{
    		cout << "I'm thread " << LThreadId << endl;
    		this_thread::sleep_for(1s);
    	}
    }
    
    int main()
    {
    	vector<thread> threads;
    
    	//1~10의 thread ID를 인자로 넘겨줘서 설정함.
    	for (int i = 0; i < 10; i++)
    	{
    		int threadid = i + 1;
    		threads.push_back(thread(ThreadMain, threadid));
    	}
    
    	for (thread& t : threads)
    		t.join();
    }

     

    1~10까지의 스레드ID를 각각의 스레드에 할당합니다.

    그리고 출력해보면, 1~10까지의 스레드 ID가 출력이 됩니다.

    멀티스레드 환경이다보니 cout을 할 때 겹치기도 합니다.

     

    그러면 LThreadID변수 선언부에서 thread_local이라는 키워드를 제거하면 어떻게 될까요?

    이렇게 threadID가 10으로만 할당되는 것을 볼 수 있습니다. 스레드가 개별적인 전역변수 공간 TLS를 갖지 못하기 때문입니다.

     

    이상으로 TLS(Thread Local Storage) 에 대한 포스팅을 마치도록 하겠습니다. 감사합니다.

    728x90

    댓글

Designed by Tistory.