기본 콘텐츠로 건너뛰기

라벨이 thread인 게시물 표시

std::thread에서 클래스 메소드 호출하기

C++11이 나온지 어언 3년... 그동안 GCC도 많이 발전하고 해서, 귀찮은 pthread_* 함수를 쓰는 것보다, 잘 감싼 std::thread를 써보고 있다. 딱히 커다란 장단점은 찾아볼 수 없지만, 콜백 함수 형태에 구애받지 않는다. C++11이 갖는 꽃별천지 언어특성과 표준라이브러리가 만나 그렇게 할 수 있는 것이지만, 자세한 설명은 생략한다... (응?) 보통 일반 함수를 쓸 경우, 아래와 같이 쓸 수 있다. void cb_func1(void) { /* ... */ } void cb_func2(int i) { /* ... */ } void init(void) { std::thread t1(cb_func1); std::thread t2(cb_func1, 10); t1.join(); t2.join(); } 그러면 메소드를 쓰다면...? 메소드 포인터 다음에 객체 포인터를 넣어서 해결할 수 있다. class MyThread { public: MyThread() { m_th = std::thread(&MyThread::proc, this); m_th.detach(); } private: void proc(void) { /* ... */ } private: std::thread m_th; }; 요로코롬 할 수 있다. 물론 밖에서 호출할 때는 "this" 대신에 해당 객체 포인터를 넘겨야 제대로 동작한다.

OpenMP

OpenMP는 다양한 플랫폼 에서 C/C++/Fortran에서 병렬처리 를 손쉽게 해주는 API일종이다. 공식 홈페이지는 http://www.openmp.org 이다. 뭔말인고 하니, 병렬처리 프로그래밍하려면 UNIX에서 fork/ipc나 pthread 등등 다양한 API에 대해 공부해야하고, 이것을 Windows로 옮길 경우, Win32API로 소스를 뜯어 고쳐야하는 불상사가 있었다. 이걸 해결하고자 OpenMP 표준을 지키는 컴파일러에서 간단하게 thread를 생성, 운용할 수 있도록 통합한 API이다. 게다가 잘만 운용하면 기존 소스를 거의 고칠 필요가 없다는 것! OpenMP는 현재 2.5(Draft는 3.0)까지 나왔으며, GCC에서 지원하는 것도 2.5까지다. 컴파일할 때 -fopenmp를 해주면 "#pragma omp" 구문을 알아서 "omp_*" 함수로 변환해준다. 아래는 간단한 예제이며, 돌려본 결과를 미리 이야기 하자면, 66.7% 이득을 봤다. 나름 쓸모 있는 녀석이긴 하지만, 제어할 수 있는 부분이 너무 적어서 과연 과학적 연산을 제외하고 일반적인 상품(게임 클라이언트)에 쓸모가 있을런지는 모르겠다. 테스트 환경 Linux 2.6.23 AMD Athlon 64 X2 Dual Core 3800+ RAM 2G GCC 4.1.2 GLIBC 2.7 CMAKE 2.4 먼저 소스 파일(openmp.c) #include <pthread.h> #include <sys/time.h> #include <omp.h> #include <stdio.h> #define __restrict__ restrict static const size_t gTestCount = 10000000; static const size_t gArraySize = 32*32; long long getTimestamp(void) { static __thread struct timev...

TLS - Thread Local Storage

쓰레드를 돌리다보면 해당 쓰레드에서만 유효한 변수를 만들고 싶을 때가 있다. 그럴 때 어떻게 해야할까? 쓰레드 개수만큼 벡터를 잡고, 해당 쓰레드마다 벡터 인덱스를 넘겨주는 것도 나름 방법이지만, 이러한 경우를 위해 TLS라는 것이 존재한다. 축약처럼 쓰레드 안에서만 따로 스토리지를 할당한 것인데, 일반 프로세스의 스텍과 비슷하나 그 크기는 프로세스 것보다 당연히 작고 제약이 심한 편이다. 뭐 암튼 그런게 있다고 치자. * GCC 메뉴얼 보면 TLS가 아니라 TSD(Thread Storage Duration)이라고 표현하였는데 대충 같은 말이다. 이것을 위해 POSIX는 pthread_key_create, pthread_get/setspecific 등 함수를 마련해놨지만 눈만 팽글팽글 돌고, 소스만 지저분해져 보일 것 같다. 귀찮으면 C99, C++98 표준 __thread 키워드를 사용하자. MSDN에 보니 __thread가 없어 보인다. 이가 없으면 잇몸으로라도... #define __thread __declspec( thread ) 대충 이 정도면 될 듯하다. 자자 각설하고, __thread란 키워드는 TLS에 변수를 선언해주는 일을 한다. 위에 나열한 pthread_* 함수를 호출하는 것으로 컴파일러가 대신 해석해주는 것일 수도 있으나 이건 가정이므로 넘어가고. 사용에 주의해야할 점은 아래와 같다. (대충대충 표준하고 MSDN 보면서 정리한 것임) 글로벌 변수나 static 변수에만 사용 가능하다. - function 안에 local 변수가 static이 아니라면 뭐더게 TLS에 저장할까? 당연히 그럴 필요가 없기 때문에 저런 제약이 있는 것이다. 이는 class에서 멤버 변수에도 적용한 법칙이다. static으로 선언한 멤버 변수에만 저 키워드를 사용할 수 있다. SO(DLL)과 로컬 영역을 넘나들면 뻑난다. - ... 그러니까 쓰지마라. 왜? 타입에 대한 한정자로 사용이 불가능하다. - const처럼 쓰지 말라는 것이고, 무...

POSIX's thread tips

쓰레드 자신에 대한 핸들을 알고 싶다면, pthread_self라는 전역 변수를 사용할 것. 두 쓰레드 핸들을 비교하고 싶다면 pthread_equal(핸들1,핸들2)을 사용한다. 둘이 같으면 0이 아닌 값이 나온다. 쓰레드 Concurrency를 확인/설정하고 싶으면 pthread_get/setconcurrency를 사용할 것. CPU점유를 다른 쓰레드에게 양보하고 싶으면 pthread_yeild가 있다. Mutex Lock을 부모 자식 프로세스 간에 공유하고 싶다면 속성에 pthread_mutexattr_get/setpshared을 이용하여 PTHREAD_PROCESS_SHARED을 세팅한다. 컨디션 변수에도 비슷한 것이 있다. 원본 위치: http://purewell.egloos.com/3398251

POSIX thread's condition

이런 상황을 생각해보자. 쓰레드가 있고, 그것은 평상시에 자는 상태(CPU점유율 0%)이다. 그런데 문득 할 일이 생겨서 침 흘리며 자고 있는 쓰레드를 두들겨 깨우고 싶다. 어떻게 하면 좋을까? volatile bool gWakeUp(false); void* _thr(void*) {     while (!gWakeUp) usleep(1000*1000);     // something... } int main(int,char**) {     // ... init thread.     gWakeUp = true;     return 0; } 이러면 쓰것나? 뭔가 찜찜허다. gWakeUp이 true로 바뀌더라도 _thr는 최악의 경우 1초 뒤에 반응을 보일 것이다. 아힝~* 싫어~* 그래서 나온 녀석이 Condition이다. 술 먹기 전에 한 번 먹고, 먹은 다음 날 한 번 먹는다는 그것!...은 아니다. #include <cstdarg> #include <pthread.h> #include <iostream> using namespace std; pthread_cond_t cond; pthread_mutex_t mtx; pthread_attr_t attr; // Just for console. pthread_mutex_t console_lock; void display(const char* fmt, ...) {     pthread_mutex_lock(&console_lock);     va_list lst;     va_start(lst, fmt);     vfprintf(stderr, fmt, lst);     va_end(lst);   ...