pthread의 pthread_create 함수에서 람다(lambda)를 사용한 예제입니다.
람다를 사용하면 따로 함수를 선언하지 않고 코드 내에 람다를 정의한 후, pthread_create에서 바로 사용할 수 있습니다.
주의할 점은 람다 함수에서 지역변수만 접근 가능합니다.
윈도우의 경우 pthread를 Visual Studio에서 사용하려면 다음 포스트를 참고하세요.
Visual Studio 2019에서 pthread 사용하는 방법
https://webnautes.tistory.com/1452
2021. 01. 16 최초작성
2021. 01. 28 최종작성
= 는 값 전달이고 &는 참조 전달이라고 하는데 테스트해본 결과는 좀 다른 듯합니다. =를 사용하면 지정한 변수만 값을 변경할 수 있고 &를 사용하면 따로 변수 지정을 하지 않아도 모든 로컬 변수의 값을 변경할 수 있습니다.
람다 함수에서 =를 사용하면
#ifdef _MSC_VER #define HAVE_STRUCT_TIMESPEC #endif #include <pthread.h> #include <stdio.h> #include <stdlib.h>
template <typename Fx> void* start_routine_t(void* arg) { Fx* f = (Fx*)arg; return (*f)(); }
int main(int argc, char* argv[]) { pthread_t threads;
int x = 1; int y = 2; int sum = 0;
auto add = [=, &sum]() // 지정한 sum만 값 변경 가능 { x = 5; y = 6; sum = x + y; return nullptr; };
pthread_create(&threads, nullptr, start_routine_t<decltype(add)>, &add);
pthread_join(threads, nullptr); printf("%d + %d = %d\n", x, y, sum);
return 0; } |
다음처럼 에러가 납니다.
Ubuntu
webnautes@webnautes-pc:~$ g++ -o test test.cpp -lpthread test.cpp: In lambda function: test.cpp:24:7: error: assignment of read-only variable ‘x’ x = 5; ^ test.cpp:25:7: error: assignment of read-only variable ‘y’ y = 6; |
Visual Studio 2019
Build started... 1>------ Build started: Project: pthread example, Configuration: Debug x64 ------ 1>main.cpp 1>C:\Users\webnautes\source\repos\pthread example\pthread example\main.cpp(24,3): error C3491: 'x': a by copy capture cannot be modified in a non-mutable lambda 1>C:\Users\webnautes\source\repos\pthread example\pthread example\main.cpp(25,3): error C3491: 'y': a by copy capture cannot be modified in a non-mutable lambda 1>Done building project "pthread example.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== |
에러나는 변수 수정하는 부분을 주석처리하면 문제가 해결됩니다.
#ifdef _MSC_VER #define HAVE_STRUCT_TIMESPEC #endif #include <pthread.h> #include <stdio.h> #include <stdlib.h>
template <typename Fx> void* start_routine_t(void* arg) { Fx* f = (Fx*)arg; return (*f)(); }
int main(int argc, char* argv[]) { pthread_t threads;
int x = 1; int y = 2; int sum = 0;
auto add = [=, &sum]() // 지정한 sum만 값 변경 가능 { // x = 5; // y = 6; sum = x + y; return nullptr; };
pthread_create(&threads, nullptr, start_routine_t<decltype(add)>, &add);
pthread_join(threads, nullptr); printf("%d + %d = %d\n", x, y, sum);
return 0; } |
webnautes@webnautes-pc:~$ ./test 1 + 2 = 3 |
람다 함수에서 &를 사용하면 따로 변수를 지정하지 않아도 모든 지역변수에 접근가능합니다.
#ifdef _MSC_VER #define HAVE_STRUCT_TIMESPEC #endif #include <pthread.h> #include <stdio.h> #include <stdlib.h>
template <typename Fx> void* start_routine_t(void* arg) { Fx* f = (Fx*)arg; return (*f)(); }
int main(int argc, char* argv[]) { pthread_t threads;
int x = 1; int y = 2; int sum = 0;
auto add = [&]() // &로 바꾸면 변수를 지정하지 않아도 모든 변수 변경 가능 { x = 5; y = 6; sum = x + y; return nullptr; };
pthread_create(&threads, nullptr, start_routine_t<decltype(add)>, &add);
pthread_join(threads, nullptr); printf("%d + %d = %d\n", x, y, sum);
return 0; } |
webnautes@webnautes-pc:~$ ./test
5 + 6 = 11
람다 함수에 전달되는 아규먼트가 변하는 경우에 유의할 점은 전달받은 후, 로컬 변수에 대입해놓아야 하는 점입니다.
#ifdef _MSC_VER #define HAVE_STRUCT_TIMESPEC #include <windows.h> //for Sleep #else #include <unistd.h> // for sleep #endif #include <pthread.h> #include <stdio.h> #include <stdlib.h>
template <typename Fx> void* start_routine_t(void* arg) { Fx* f = (Fx*)arg; return (*f)(); }
const char* list[] = { "00000", "11111", "22222" };
int main(int argc, char* argv[]) { pthread_t threads;
for (int i = 0; i < 3; i++) { auto add = [=, &i]() { // 지역변수에 대입하여 사용하지 않으면 변수값 변화가 반영되어 // 문제된다. int k = i; const char* c = list[k];
while (1) { printf("[%d] %s\n", k, c); }
return nullptr; };
pthread_create(&threads, nullptr, start_routine_t<decltype(add)>, &add); #ifdef _MSC_VER Sleep(5); // 스레드 함수의 지역 변수에 대입될 시간을 준다. #else sleep(5); #endif }
while (1);
return 0; }
|
참고
https://programmer.help/blogs/c-binds-lambda-expressions-to-callback-functions.html