pthread_create线程创建的过程剖析
http://blog.csdn.net/wangyin159/article/details/47082125
在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程。线程创建失败时,它可能会返回ENOMEM或EAGAIN。这篇文章主要讨论线程创建过程中碰到的一些问题和解决方法。
创建线程
首先,本文用的实例代码example.c:
|
/* example.c*/ sleep(30); int main(int argc,char **argv) |
编译,执行下面命令:
|
# example.c -lpthread -o example -g |
用strace工具跟踪线程创建的过程:
|
# strace ./example |
Strace工具输出:
|
getrlimit(RLIMIT_STACK, {rlim_cur=10240*1024, rlim_max=RLIM_INFINITY}) = 0 |
由上表中的输出可以看出创建线程过程中的调用步骤:
- 通过系统调用getrlimit() 获取线程栈的大小(参数中的RLIMIT_STACK),在我的环境里(CentOS6),缺省值是10M。
- 调用mmap2()分配内存,大小为10489856字节,合10244K,比栈空间大了4K。返回0xb6d1c000。
- 调用mprotect(),设置个内存页的保护区(大小为4K),页面起始地址为0xb6d1c000。这个页面用于监测栈溢出,如果对这片内存有读写操作,那么将会触发一个SIGSEGV信号。下面布局图中的红色区域既是。
- 调用clone()创建线程。调用的第一个参数是一个地址:栈底的地址(这里具体为0xb771c494)。栈空间的内存使用,是从高位内存开始的。
从/proc/<pid>/smaps文件里,我们可以清楚地看到栈内存的映射情况:
|
090e0000-09101000 rw-p 00000000 00:00 0 [heap] |
从上面的映射文件的深蓝色部分中,我们看到,栈的空间总共为10244Kb,内存段是从b6d1d000到b771e000。从strace的输出中,我们看到栈底的地址为0xb771c494,那么,从0xb771c494到b771e000这段内存是做什么用的呢?它就是线程的TCB(thread's control block)和TLS区域(thread's local storage)。具体的线程内存空间布局如下:

GLIBC2.5与2.8
研究GLIBC2.5和2.8里的pthread_create()相关代码,会发现在mmap()调用失败并返回ENOMEM时,作了点变动,新版里替换了错误码。
V2.5相关代码.../nptl/allocatestack.c:
|
mem = mmap (NULL, size, prot, if (__builtin_expect (mem == MAP_FAILED, 0)) |
V2.8里的.../nptl/allocatestack.c:
|
mem = mmap (NULL, size, prot, if (__builtin_expect (mem == MAP_FAILED, 0)) return errno; |
如上面的代码片段所示,在V2.5,简单地将mmap()调用结果返回给用户,而在V2.8里,如果mmap()返回ENOMEM,那么GLIBC会将错误码改成EAGAIN再返回。
为什么pthread_create()会调用失败?
随着运行中的线程数量的增大,pthread_create()失败的可能性也会增大。因为这会使分配给线程的内存空间(比如说线程栈)累积太多,导致mmap()系统调用失败。
比如说,/proc/<pid>/smaps里有这样一个内存映射片段:
|
[...] |
可用的内存空间是最后一个内存段和[stack]标签之间的空间:0x7F8F5000 - 0x7F33C000 = 0x5B9000 = 6000640字节(也就是6MB)。按缺省配置,小于一个线程栈的空间(10MB)。这时再创建线程就要失败。
解决方法
通常情况下,缺省10M的线程栈空间显然是太大了,所以建议通过调用pthread_attr_setstacksize()API来改变线程栈的大小。比如说以下代码片段:
pthread_create线程创建的过程剖析的更多相关文章
- pthread_create线程创建的过程剖析(转)
概述 在Linux环境下,pthread库提供的pthread_create()API函数,用于创建一个线程.线程创建失败时,它可能会返回ENOMEM或EAGAIN.这篇文章主要讨论线程创建过程中碰到 ...
- windows进程/线程创建过程 --- windows操作系统学习
有了之前的对进程和线程对象的学习的铺垫后,我们现在可以开始学习windows下的进程创建过程了,我将尝试着从源代码的层次来分析在windows下创建一个进程都要涉及到哪些步骤,都要涉及到哪些数据结构. ...
- 理解Android线程创建流程
copy from : http://gityuan.com/2016/09/24/android-thread/ 基于Android 6.0源码剖析,分析Android线程的创建过程 /androi ...
- Linux线程-创建
Linux的线程实现是在内核以外来实现的,内核本身并不提供线程创建.但是内核为提供线程[也就是轻量级进程]提供了两个系统调用__clone()和fork (),这两个系统调用都为准备一些参数,最终都用 ...
- linux c编程:线程创建
前面章节中介绍了进程.从这一章开始介绍线程.进程和线程的差别是什么呢: 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是进程的一个实 ...
- 理解Android线程创建流程(转)
/android/libcore/libart/src/main/java/java/lang/Thread.java /art/runtime/native/java_lang_Thread.cc ...
- Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- Posix线程编程指南(1) 线程创建与取消
线程创建 1.1 线程与进程 相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列.在串行程序基础上引入线程和进程是为了提高程序的 ...
- Unix 环境高级编程---线程创建、同步、
一下代码主要实现了linux下线程创建的基本方法,这些都是使用默认属性的.以后有机会再探讨自定义属性的情况.主要是为了练习三种基本的线程同步方法:互斥.读写锁以及条件变量. #include < ...
随机推荐
- Node.js之Promise
2015年发布了ES6标准,所谓 Promise,就是ES6标准的一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步 ...
- 【原创】有关Silverlight中“DataGrid中单元格动态绑定ComboBox单击时数据项莫名被清除 ”的解决方案及思路。
今天上班遇到一个很古怪的问题,搞了半天愣是没找到原因.是这样的,在Datagrid中有绑定一个ComboBox列,其不包含在 model数据中,而是单独在LoadingRow事件中去 从数据库拿数据绑 ...
- Maximal Square
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and ret ...
- C语言 百炼成钢12
//题目34:对10个数进行排序 #include<stdio.h> #include<stdlib.h> //分析:使用冒泡排序 void main(){ ] = { , , ...
- Ace 动画应用实例 ------启动欢迎界面
仔细观察手机应用很多都用到了动画效果 那么咱们也做一个 除了位移没有使用 其他都有 布局随便放张图片 public class SplashActivity extends Activity { pr ...
- [C++] 在Visual Studio工程中管理C++第三方库
目前的项目依赖于很多第三方库,每次要再一个新的环境编译/运行,都要花很长时间先编译/安装各种第三方库,而且会出现各种问题,因此决定将所有第三方库编译好之后,放入工程的子目录中,以后就不用重复编译了. ...
- 在View页面,使用@if(){ }输出判断正确的内容
@if (true) { Html.Raw("已结束"); } 发现这段代码是正确,但是页面不输出"已结束"三个字,但是也不报错 @if (DateTime.N ...
- 20135223/20135234/20135229小组——亚博 Arduino智能小车实践报告
实验名称:Arduino智能小车组装和综合测试 实验小组成员:20135223何伟钦 20135234马启扬 20135229吕松鸿 实验日期:2015.10.27—2015.11.3 实验时长:24 ...
- Jenkins进阶系列之——12详解Jenkins节点配置
2014-03-02:修正对于lable标签的理解.(1.532.1版本已经给出了官方解释) 2013-12-22:添加JNLP端口修改,修改了一些错误. Jenkins有个很强大的功能:分布式构建( ...
- 在ubuntu server上安装沸腾时刻环境
1. 安装php5.6 http://phpave.com/upgrade-to-php-56-on-ubuntu-1404-lts/ 按照这篇文章的顺序来做,可以安装最新5.6版本php 安装好了以 ...