C/C++ Linux pthread_attr_setstacksize 設定執行緒堆疊大小用法

本篇 ShengYu 介紹 C/C++ Linux/Unix 執行緒 pthread_attr_setstacksize() 用法,pthread_attr_setstacksize() 是用來設定該執行緒的堆疊大小。

pthread_attr_setstacksize 基本用法

pthread_create() 建立執行緒時沒有設定堆疊大小的話會採用系統的預設值,在 shell 下輸入 ulimit -s 就可以看到目前系統的設定值,單位為 KB,如下所示目前數值為 8192KB,也就是 8M,也可以透過 ulimit 來改變系統預設的 stack size 大小。

1
2
$ ulimit -s
8192

這邊介紹不改動系統的預設值,而是透過 pthread_attr_setstacksize 來改變執行緒的 stack 堆疊大小。
pthread 堆疊最小值定義為 PTHREAD_STACK_MIN,也就是 16384bytes,pthread_attr_setstacksize() 設定小於 PTHREAD_STACK_MIN 的話會回傳 0 (表示設定失敗),

以下簡單示範如何使用 pthread_attr_setstacksize(),stack size 要在執行緒建立之前設定,也就是傳入 attr 給 pthread_create,執行緒建立後是無法再改動 stack size 的。

cpp-pthread_attr_setstacksize.cpp
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
38
39
// g++ cpp-pthread_attr_setstacksize.cpp -o a.out -pthread
#include <stdio.h>
#include <pthread.h>

void * foo(void *arg) {
printf("foo\n");
return NULL;
}

int main() {
pthread_t t1;
pthread_attr_t attr;
int ret;
size_t stacksize = 65536;

ret = pthread_attr_init(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_init\n");
}

ret = pthread_attr_setstacksize(&attr, stacksize);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_setstacksize\n");
}

ret = pthread_create(&t1, &attr, foo, NULL);
if (ret != 0) {
fprintf(stderr, "Error: pthread_create\n");
}

pthread_join(t1, NULL);

ret = pthread_attr_destroy(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_destroy\n");
}

return 0;
}

補充:若要使用 PTHREAD_STACK_MIN 定義的話,需 include <limits.h>

設定完後,可以使用 pthread_attr_getstacksize 來取得 stack size,如下面範例,

cpp-pthread_attr_setstacksize2.cpp
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
38
39
40
41
42
43
44
45
46
// g++ cpp-pthread_attr_setstacksize2.cpp -o a.out -pthread
#include <stdio.h>
#include <pthread.h>

void * foo(void *arg) {
printf("foo\n");
return NULL;
}

int main() {
pthread_t t1;
pthread_attr_t attr;
int ret;
size_t stacksize = 65536;

ret = pthread_attr_init(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_init\n");
}

ret = pthread_attr_setstacksize(&attr, stacksize);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_setstacksize\n");
}

size_t stacksize2;
ret = pthread_attr_getstacksize(&attr, &stacksize2);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_getstacksize\n");
}
printf("stack size: %zu\n", stacksize2);

ret = pthread_create(&t1, &attr, foo, NULL);
if (ret != 0) {
fprintf(stderr, "Error: pthread_create\n");
}

pthread_join(t1, NULL);

ret = pthread_attr_destroy(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_destroy\n");
}

return 0;
}

結果輸出如下,

1
2
stack size: 65536
foo

不過這樣算是從 attr 這變數裡取出 stack size,不算真正這個 thread 的 stack size,正確做法應該如下,

以下是在 foo 函數內取得該 thread 的 stack size,是透過 pthread_getattr_np 函式重新取得 attr 變數後再用 pthread_attr_getstacksize 取得 stack size。
請注意,pthread_getattr_np 函數並不是 POSIX 標準的一部分,但它在一些 POSIX 系統上是可用的。這個函式可以用來獲取執行緒的屬性,包括 stack 大小等資訊。以下是範例程式碼:

cpp-pthread_attr_setstacksize3.cpp
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// g++ cpp-pthread_attr_setstacksize3.cpp -o a.out -pthread
#include <stdio.h>
#include <pthread.h>

void printStackSize() {
pthread_attr_t attr;
int ret;
size_t stacksize;

ret = pthread_getattr_np(pthread_self(), &attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_getattr_np\n");
}

ret = pthread_attr_getstacksize(&attr, &stacksize);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_getstacksize\n");
}

printf("stack size: %zu\n", stacksize);
}

void * foo(void *arg) {
printf("foo\n");
printStackSize();
return NULL;
}

int main() {
pthread_t t1;
pthread_attr_t attr;
int ret;
size_t stacksize = 65536;

ret = pthread_attr_init(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_init\n");
}

ret = pthread_attr_setstacksize(&attr, stacksize);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_setstacksize\n");
}

ret = pthread_create(&t1, &attr, foo, NULL);
if (ret != 0) {
fprintf(stderr, "Error: pthread_create\n");
}

pthread_join(t1, NULL);

ret = pthread_attr_destroy(&attr);
if (ret != 0) {
fprintf(stderr, "Error: pthread_attr_destroy\n");
}

return 0;
}

結果輸出如下,

1
2
stack size: 65536
foo

為什麼不是在 foo 裡用 pthread_attr_init 後再用 pthread_attr_getstacksize 取得 stack size 呢?
因為 pthread_attr_init 後再用 pthread_attr_getstacksize 取得 stack size 是系統預設的 stack size,不是你設定後的 stack size。

其它參考
pthread_attr_setstacksize(3) - Linux manual page
https://man7.org/linux/man-pages/man3/pthread_attr_setstacksize.3.html
线程堆栈大小 pthread_attr_setstacksize 的使用
https://blog.csdn.net/godleading/article/details/7997630

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ Linux pthread_attr_getstacksize 取得執行緒堆疊大小用法
C/C++ Linux/Unix 讓執行緒跑在指定 CPU 的方法 sched_setaffinity
C/C++ Linux/Unix pthread 建立多執行緒用法與範例
C++ std::thread 建立多執行緒用法與範例