一 Pthread 并发编程——深入剖析线程基本元素和状态( 三 )


#include <stdio.h>#include <pthread.h>#include <stdlib.h>#define MiB * 1 << 20int times = 0;void* stack_overflow(void* args) {printf("times = %d\n", ++times);char s[1 << 20]; // 1 MiBstack_overflow(NULL);return NULL;}int main() {pthread_attr_t attr;pthread_attr_init(&attr); // 对变量 attr 进行初始化操作pthread_attr_setstacksize(&attr, 24 MiB); // 设置栈帧大小为 24 MiB 这里使用了一个小的 trick 大家可以看一下 MiB 的宏定义pthread_t t;pthread_create(&t, &attr, stack_overflow, NULL);pthread_join(t, NULL);pthread_attr_destroy(&attr); // 释放线程属性的相关资源return 0;}上面的程序执行结果如下图所示:

一 Pthread 并发编程——深入剖析线程基本元素和状态

文章插图
从上面程序的执行结果来看我们设置的 24 MB 的栈空间大小起到了效果,我们可以通过线程的递归次数可以看出来我们确实申请了那么大的空间 。在上面的程序当中我们对属性的操作如下,这也是对属性操作的一般流程:
  • 使用 pthread_attr_init 对属性变量进行初始化操作 。
  • 使用各种各样的函数对属性 attr 进行操作,比如 pthread_attr_setstacksize,这个函数的作用就是用于设置线程的栈空间的大小 。
  • 使用 pthread_attr_destroy 释放线程属性相关的系统资源 。
自己为线程的栈申请空间在上一小节当中我们通过函数 pthread_attr_setstacksize 给栈空间设置了新的大小,并且使用程序检查验证了新设置的栈空间大小,在这一小节当中我们将介绍使用我们自己申请的内存空间也可以当作线程的栈使用 。我们将使用两种方法取验证这一点:
  • 使用 malloc 函数申请内存空间,这部分空间主要在堆当中 。
  • 使用 mmap 系统调用在共享库的映射区申请内存空间 。
使用 malloc 函数申请内存空间#include <stdio.h>#include <pthread.h>#include <stdlib.h>#define MiB * 1 << 20int times = 0;staticvoid* stack_overflow(void* args) {printf("times = %d\n", ++times);char s[1 << 20]; // 1 MiBstack_overflow(NULL);return NULL;}int main() {pthread_attr_t attr;pthread_attr_init(&attr);void* stack = malloc(2 MiB); // 使用 malloc 函数申请内存空间 申请的空间大小为 2 MiBpthread_t t;pthread_attr_setstack(&attr, stack, 2 MiB); // 使用属性设置函数设置栈的位置 栈的最低地址为 stack 栈的大小等于 2 MiBpthread_create(&t, &attr, stack_overflow, NULL);pthread_join(t, NULL);pthread_attr_destroy(&attr); // 释放系统资源free(stack); // 释放堆空间return 0;}上述程序的执行结果如下图所示:
一 Pthread 并发编程——深入剖析线程基本元素和状态

文章插图
从上面的执行结果可以看出来我们设置的栈空间的大小为 2MB 成功了 。在上面的程序当中我们主要使用 pthread_attr_setstack 函数设置栈的低地址和栈空间的大小 。我们申请的内存空间内存布局大致如下图所示:
一 Pthread 并发编程——深入剖析线程基本元素和状态

文章插图
使用 mmap 申请内存作为栈空间#define _GNU_SOURCE#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <sys/mman.h>#define MiB * 1 << 20#define STACK_SIZE 2 MiBint times = 0;staticvoid* stack_overflow(void* args) {printf("times = %d\n", ++times);char s[1 << 20]; // 1 MiBstack_overflow(NULL);return NULL;}int main() {pthread_attr_t attr;pthread_attr_init(&attr);void* stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);if (stack == MAP_FAILED)perror("mapped error:");pthread_t t;pthread_attr_setstack(&attr, stack, STACK_SIZE);pthread_create(&t, &attr, stack_overflow, NULL);pthread_join(t, NULL);pthread_attr_destroy(&attr);free(stack);return 0;}

经验总结扩展阅读