转:http://blog.sina.com.cn/s/blog_6abf2c040101fpca.html
原文地址:【原】Linux中pthread_create函数的实现作者:jiq408694711

今天看到看到有人介绍说Linux中线程怎么么好,切换代价极低,响应快,能有效利用多处理器机制。然后我就纳闷了:Linux中线程不是完全和进程一样,不进行任何区分么?怎么就有这些独特的好处了?

于是我跑到Linux内核源码里面想找找看pthread_create函数的实现,但是没找到。

后来看到有人说:

在这里下载glibc源代码:http://ftp.gnu.org/pub/gnu/glibc/glibc-2.3.5.tar.gz
tar zxvf glibc-2.3.5.tar.gz解开压缩包
cd glibc-2.3.5/nptl
该目录下的pthread_create.c即为你想看的实现

然后才知道这个函数是在Glibc的库里面实现的!!!我们先看看什么是glibc:

========================================================================================

glibc

glibc是gnu发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。

glibc除了封装linux操作系统所提供的系统服务外,它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX 通行的标准,可以想见其内容包罗万有。

而就像其他的 UNIX 系统一样,其内含的档案群分散于系统的树状目录结构中,像一个支架一般撑起整个作业系统。在 GNU/Linux 系统中,其C函式库发展史点出了GNU/Linux 演进的几个重要里程碑,用glibc 作为系统的C函式库,是GNU/Linux演进的一个重要里程碑。

功能实现主要的如下:

  (1)string,字符串处理

  (2)signal,信号处理

  (3)dlfcn,管理共享库的动态加载

  (4)direct,文件目录操作

  (5)elf,共享库的动态加载器,也即interpreter

  (6)iconv,不同字符集的编码转换

  (7)inet,socket接口的实现

  (8)intl,国际化,也即gettext的实现

  (9)io

  (10)linuxthreads

  (11)locale,本地化

  (12)login,虚拟终端设备的管理,及系统的安全访问

  (13)malloc,动态内存的分配与管理

  (14)nis

  (15)stdlib,其它基本功能

   在 GNU/Linux 系统中,其 C 函式库的发展史点出了 GNU/Linux 演进的几个重要里程碑,由此可以突显出 C 函式库在系统中的地位与重要性。早期的 GNU/Linux 系统不支援可分享函式库,因此所有的应用程式都是以静态连结的方式存于系统中。直到 1995-1996 年 libc5 问世以后,系统才开始支援 ELF 可分享函式库,同时该版的 C 函式库也?作了其他 UNIX 上大部分的功能与函式群,可谓 GNU/Linux 发展上的一大进步。

  然而 libc5 在程式国际化 (I18N) 与本土化 (L10N) 方面的支援很差,故那个时候若要开发所谓中文化的程式,就非得自行?作一套标准不可。直到一两年后, GNU/Linux 换用了 GNU 所开发的 glibc-2.0 做为其 C 函式库后,其国际化与本土化的支援才开始起步,后经 glibc-2.1,到了现在的 2.2 版,整个多国语文的开发环境才大至成熟。

  用 glibc 做为系统的 C 函式库,是 GNU/Linux 演进的一个重要里程碑。

比起过去的 libc5,glibc 系列 (一般又称之为 libc6) 除了有完整的国际化与本土化支援外,同时还符合许多标准与规格,使得在 glibc 下开发的程式可以很容易移植到其他 UNIX 平台去。这些标准包括:

  ISO C:

  ISO C 是 International Standard for the C programming language 的缩写,此标准明定了 C 语言的语法,标准 C 函式库应具备那些标头档、巨集定义、函式与物件 .... 等等,几乎在任何平台上的 C 语言 (包括非 UNIX 平台) 都支援此标准。

  POSIX:

  POSIX 是 Portable Operating System Interface for Computer Environments 的缩写,它是 ISO C 的延伸,明定了一个可移植的作业系统所应具备种种条件,其范围不只有系统函式库而已,还同时包括一些标准的工具程式、系统核心应有的特色与?作、以及在 C 函式库中某些与作业系统相关的低阶控制支援 (如系统呼叫窗口) 等等。由于 glibc 是完全按照 POSIX 的标准制作的,同时搭配了符合 POSIX 标准的 Linux 核心,故在此环境下开发的程式可以做到完全符合 POSIX 的规格。

  Berkeley Unix:

  Berkeley Unix 泛称柏克莱大学所开发的 UNIX 系列作业系统,包括 4.2 BSD、4.3 BSD、4.4 BSD 以及早期的 SunOS。这些系统的 C 函式库中有许多杰出的设计,但却没有在上述两个标准中,包括 select() 函式、sockets .... 等等,这些在 glibc 中都有支援。

等等。。。

====================================================================================

======================================pthread_create.c===============================

下面看看这个函数的源码吧(只保留重要的几行):

int
__pthread_create_2_1 (newthread, attr, start_routine, arg)
     pthread_t *newthread;
     const pthread_attr_t *attr;
     void *(*start_routine) (void *);
     void *arg;
{
  STACK_VARIABLES;
  const struct pthread_attr *iattr;
  struct pthread *pd;
  //。。。

  上面省略的代码主要是:分配栈空间等,初始化pthread结构pd和pthread_attr结构iattr,其中内容基本上是从其parent拷贝过来的,然后设置一些必要的标志

/ Start the thread.  /
  err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
 }
versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);

=======================================createthread.c=====================================

在createthread.c中create_thread方法:

static int
create_thread (struct pthread *pd, const struct pthread_attr *attr,
        STACK_VARIABLES_PARMS)
{

/ Actually create the thread.  /
  int res = do_clone (pd, attr, clone_flags, start_thread, STACK_VARIABLES_ARGS, stopped);

}

===================================createthread.c============================

static int
do_clone (struct pthread *pd, const struct pthread_attr *attr,
   int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS,
   int stopped)
{
#ifdef PREPARE_CREATE
  PREPARE_CREATE;
#endif

if (stopped)
    / We Make sure the thread does not run far by forcing it to get a
       lock.  We lock it here too so that the new thread cannot continue
       until we tell it to.  /
    lll_lock (pd->lock);

/ One more thread.  We cannot have the thread do this itself, since it
     might exist but not have been scheduled yet by the time we've returned
     and need to check the value to behave correctly.  We must do it before
     creating the thread, in case it does get scheduled first and then
     might mistakenly think it was the only thread.  In the failure case,
     we momentarily store a false value; this doesn't matter because there
     is no kosher thing a signal handler interrupting us right here can do
     that cares whether the thread count is correct.  /
  atomic_increment (&__nptl_nthreads);

if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
    pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
    {
      atomic_decrement (&__nptl_nthreads); / Oops, we lied for a second.  /

/ Failed.  If the thread is detached, remove the TCB here since
  the caller cannot do this.  The caller remembered the thread
  as detached and cannot reverify that it is not since it must
  not access the thread descriptor again.  /
      if (IS_DETACHED (pd))
 __deallocate_stack (pd);

return errno;
    }

/ Now we have the possibility to set scheduling parameters etc.  /
  if (__builtin_expect (stopped != 0, 0))
    {
      INTERNAL_SYSCALL_DECL (err);
      int res = 0;

/ Set the affinity mask if necessary.  /
      if (attr->cpuset != NULL)
 {
   res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
      sizeof (cpu_set_t), attr->cpuset);

if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
     {
       / The operation failed.  We have to kill the thread.  First
   send it the cancellation signal.  /
       INTERNAL_SYSCALL_DECL (err2);
     err_out:
#if __ASSUME_TGKILL
       (void) INTERNAL_SYSCALL (tgkill, err2, 3,
           THREAD_GETMEM (THREAD_SELF, pid),
           pd->tid, SIGCANCEL);
#else
       (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
#endif

return (INTERNAL_SYSCALL_ERROR_P (res, err)
        ? INTERNAL_SYSCALL_ERRNO (res, err)
        : 0);
     }
 }

/ Set the scheduling parameters.  /
      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
 {
   res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
      pd->schedpolicy, &pd->schedparam);

if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
     goto err_out;
 }
    }

/ We now have for sure more than one thread.  The main thread might
     not yet have the flag set.  No need to set the global variable
     again if this is what we use.  /
  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);

return 0;
=====================================================================================

没看出来glibc中创建线程与Linux源码的fork.c中创建进程的do_fork函数有什么明显的区别。。。

难道Linux仅仅是单纯地保留了Unix中的API,其实内在并没有任何联系?

Unix中的线程和Linux中的进程的确是有很多区别?只是Linux中不把线程和进程进行区分而已。。。。

不明白。哎~

不过Unix线程之间只要是来自同一个父线程是可以共享数据的,从这一点来看我个人认为Unix中的线程和Linux内核中实现的进程/线程不但不一样,而且还没有任何关系!!!

Linux中pthread_create函数的实现相关推荐

  1. linux中probe函数传递参数的寻找(下)

    点击打开链接 linux中probe函数传递参数的寻找(下) 通过追寻driver的脚步,我们有了努力的方向:只有找到spi_bus_type的填充device即可,下面该从device去打通,当两个 ...

  2. linux中 probe函数的何时调用的?

    点击打开链接 linux中 probe函数何时调用的 所以的驱动教程上都说:只有设备和驱动的名字匹配,BUS就会调用驱动的probe函数,但是有时我们要看看probe函数里面到底做了什么,还有传递给p ...

  3. 每天学一点儿shell:linux中时间函数的date的用法

    文章目录 1.linux中date函数格式 2.date日期函数的具体用法 2.1.获取相应格式的日期 2.2.获取相隔时间段的日期 2.2.1.获取今天的日期 2.2.2.获取昨天的日期 2.2.3 ...

  4. linux中request_region()函数的分析

    linux中request_region()函数的分析 struct resource ioport_resource = { .name = "PCI IO", .start = ...

  5. linux内核sock_sendmsg,为什么linux中sendto函数中的msg.msg_iovlen=1;

    为什么linux中sendto函数中的msg.msg_iovlen=1; | 内核中定义的sys_sendto的源码吗? 这个属于sendmsg中struct msghdr的用法问题, sys_sen ...

  6. Linux中popen函数的作用小结

    概述 popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程.这篇文章重点给大家介绍Linux中popen函数的作用,感兴趣的朋友一起看看吧 p ...

  7. Linux中fork()函数详解

    Linux中fork()函数详解 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事, ...

  8. linux 内核 fget,fgets函数 linux中fgets函数怎么用

    一个函数该如何使用?我们最先要了解的就是这个函数的语法以及具体的含义是什么,所以今天我们就来看一看fgets函数在实际的运用过程当中是如何使用的,希望能给大家带来一定的帮助. fgets函数--lin ...

  9. linux 中 sigaction 函数详解

    linux 中 sigaction 函数详解 一.函数原型 sigaction 函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作) int sigaction(int signum, ...

最新文章

  1. 猜拳小程序c语言编程,无聊的时候写的猜拳小程序
  2. SessionID 的本质
  3. SQL SERVER大话存储结构:数据库数据文件
  4. gdal库对ENVI文件的一点支持不好
  5. java中的case1怎么说_Java Cas20ServiceTicketValidator類代碼示例
  6. 如何用 IDEA 提升十倍开发效率?
  7. 在职场上被逼「造反」的文科生,半年后25k,还强硬的说我拿低了...
  8. paypal创建订单后怎么获得id_新支付无国界:PayPal注册教程
  9. 国联安 德盛 新基金 申购免手续费 产品好 利润高
  10. Timer的源码分析
  11. 一定要学会了解大数据
  12. 热播剧《延禧攻略》进入台湾2019年学测语文试题
  13. 服务器——SSL/TLS协议信息泄露漏洞(CVE-2016-2183)修复办法
  14. “蘑菇书”是怎样磨出来的?
  15. 区块链基础入门笔记 一
  16. python画圆形螺旋线_【Python基础】利用 Python 搞定精美网络图!
  17. 超详细解读OSPF Router-ID
  18. MySQL主键(primary key)的作用
  19. 哈工大政治课的一点小经验
  20. android 10bit,作为“普通用户” 我们为什么建议你不强求10bit屏幕?

热门文章

  1. TCP三次握手四次挥手详解
  2. centos 无线网络连接
  3. metalink 使用向导(整理点metalink使用资料)
  4. python global 变量_python 引用全局变量之global
  5. CRC冗余校验码及查表法
  6. 杀鸡也用牛刀,Haskell 处理 XML 文档小试
  7. Android 开发之 ContentProvider 内容提供者
  8. 一篇让读者恐怖、令微软害怕的文章
  9. WEB之CGI----CGI详解(原理,配置及访问)
  10. java中的softreference_Java中的 WeakReference 和 SoftReference