엄범


전역 함수를 threadMain으로 지정해 실행하는건 그냥 다른 언어 처럼 하면 되는데, 

객체의 메서드를 threadMain으로 지정하는건 몇 가지 신경써야 할 부분이 있다.

보통 다른 언어 같으면, `` Thread`` 클래스 상속받아서 ``c t.run()`` 해주면 끝인데, C++은 그렇지 못하다.


구식 방법

원래 클래스 내부의 메서드를 threadMain으로 지정하기 위해서는, 

threadMain가 될 메서드를 static으로 빼고,

static 메서드는 클래스 내부의 일반 멤버에 접근하지 못하기 때문에 일반 메서드의 wrapper처럼 사용하고, 진짜 _threadMain은 일반 메서드로 구성한 다음, 그 일반 메서드를 호출하기 위해

threadMain 메서드에서 ``c void*`` 형을 인자로 받은 다음에 클래스로 형변환하고, 그 클래스 포인터를 이용해 _theadMain을 호출하는 번거로운 방법을 사용해야 한다.


bind를 사용하는 방법.

```cpp

#include <functional>

#include <thread>


class TestCls {

public:

int val;

void threadMain(int d) {

printf("[1.val] = %d\n", val);

std::this_thread::sleep_for(std::chrono::seconds(2));

printf("[2.val] = %d\n", val);

}

};



int main()

{

TestCls test_cls;

test_cls.val = 1;


// [Error]   std::thread cls_thread(test_cls.threadMain, 3);

/* 안된다. 생각해보면 되면 안된다.

객체는 상태를 가지고 있는데 이런 식으로 넘기면 

test_cls.threadMain든, test_cls2.threadMain든 메서드의 주소 정보만 넘어가기 때문에

test_cls의 context에 대한 정보는 넘어가지 않는다. 

threadMain라는 함수의 내부에서 클래스의 다른 멤버 변수를 참조한다면

어떤 객체의 멤버 변수를 참조해야할지 알 수 없어진다.

그래서 1. 실행할 메서드 2. 컨텍스트(객체) 3. 인자 이렇게 넘겨줘야 한다.  */


std::thread copied_ctx_t(std::bind(&TestCls::threadMain, test_cls));

std::thread refer_ctx_t(std::bind(&TestCls::threadMain, &test_cls));

std::this_thread::sleep_for(std::chrono::seconds(1));

test_cls.val = 4;

printf("set val = 4\n");

/* 이 때, context가 참조로 넘어가는지, 값으로 넘어가는지도 중요하다. 

thread에 context를 넘기고 나서 context 객체의 변수 val이 수정될 수 있다.

값으로 넘기게 되면, 객체의 현재 상태를 박제해서 이 context 하에서 threadMain이 실행되고,

참조로 넘기게 되면, thread 코드가 실행되는 context가 변경되었을 때 반영된다. */


copied_ctx_t.join();

refer_ctx_t.join();


    return 0;

}

```

```

[1.val] = 1

[1.val] = 1

set val = 4

[2.val] = 1

[2.val] = 4

```


```cpp

std::thread no_bind_t(&TestCls::threadMain, test_cls);

```

사실 굳이 bind 붙여주지 않아도 내부적으로 알아서 해주는 듯. 

boost::thread의 경우 이렇게 넘기면 bind()로 알아서 감싸서 함수와 인자들이 internal storage로 복사된다고 나와있다.

std::thread도 boost에서 상당 부분 참고해서 만들었다고 알고있다. 대충 비슷하게 돌아갈 것 같다.

    !!!단, 이렇게 했을 때 안되는 경우가 있음. 

    ``cpp boost::thread t(&boost::asio::io_context::run, &_io_context);``는 bind하면 되고 이건 안되더라. static_cast하면 이렇게 써도 되긴 되는데, bind는 static_cast안써도 잘 되고.


람다를 사용하는 방법★

``c bind()``는 몇 가지 단점을 가지고 있어 람다를 사용하는게 좋다. 

단점 중 하나가 overloaded function에 대해서 사용하면 어떤 함수를 바인드해야할지 알 수 없기 때문에, ``cpp static_cast<>`` 해서 딱 지정해줘야한다는 점이다. 이게 상당히 귀찮다.


bind를 사용했던 코드는 이렇게 바꿀 수 있고,

```cpp

std::thread lambda_ref_thread( [&] { test_cls.threadMain(); });

std::thread lambda_copy_thread([=] () mutable { test_cls.threadMain(); });

```


``cpp threadMain(int)`` 함수가 오버로딩되었다면, 그냥 이렇게 써주면 된다. bind보다 훨씬 편하다.

```cpp

std::thread lambda_ref_thread( [&] { test_cls.threadMain(2); });

std::thread lambda_copy_thread([=] () mutable { test_cls.threadMain(2); });

```