天天看点

APUE学习(五):线程与进程(API与概念部分)

这个主要针对进程线程的api和概念来讲的,了解了后边碰到线程同步以及进程通信从原理上就会有个认识

(一)控制原语

进程&线程控制原语比较

进程原语 线程原语 描述
fork pthread_create 创建。从创建上可以看出两者的区别,strace命令跟踪到前者调用clone,后者clone&mmap2
exit pthread_exit 退出
waitpid pthread_join 等待,并得到退出状态
atexit pthread_cleanup_push 注册退出时候调用函数
getpid pthread_self 获取控制流id
abort pthread_cancel 请求非正常退出
pthread_detach 线程进入分离状态,然后自动进行资源释放,不需pthread_join处理。

关于fork 和 pthread_create这里贴的连接可以参考一下。

http://www.fuzhijie.me/?p=235   

关于pthread_join & pthread_detach刚开始看书上说明以及man page有点吃力,写了个测试就一目了然了。

/*
 *线程终止测试
 *pthread_exit(),pthread_join().
 *分离态pthread_detach()
 */

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>


void* thread_handle(void* arg)
{
  // pthread_detach(pthread_self()); //自己能使自己处理分离状态,之前写错了。现在修正
  //  sleep(4);
  
  printf("from thread_handle\n");
  return ;
  //  pthread_exit();
}

int main(int argc,char* argv[])
{
  pthread_t tid;
  int result;
  void* retvar;

  if( (result = pthread_create(&tid,NULL,thread_handle,NULL)) != 0)
    perror("pthread create error\n");

  
  if( (result = pthread_detach(tid)) != 0)
    printf("pthread detach error\n"); \\线程中使用error_no牵扯到同步与私有化问题,之前用perror也是不当的,这里给出修正

  // sleep(2);

  if( (result = pthread_join(tid,&retvar)) != 0)
    printf("pthread join error\n");

    
  printf("main exit ,and thread return %d\n",(int)result);
  exit(0);
}
           

detach之后的输出

pthread join error    

main exit,and thread return xxxx //这里thread没有执行

如果sleep(2)

pthread join error

from thread handle

main exit,and thread return xxxx  

(二) 系统实现浅析

 系统环境

$cat /proc/version

Linux version 3.0.1 ([email protected]) (gcc version 4.4.5 (Debian 4.4.5-8) ) #1 SMP Fri Aug 12 11:50:03 CST 2011

这里我创建1000个线程和1000个进程进行跟踪截取部分。

$strace -c ./my_thread
130ms
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.99    0.001170           1      1011       618 mmap2
  2.01    0.000024           0       382           clone
           
$strace -c ./my_proc
63ms
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.000166           0      1000           clone
           

线程函数在编译的时候,需要-lpthread ,也就是说系统内核没有实现线程。

在trace 函数fork  与 pthread_create的时候,两者都是通过clone实现.fork调用的clone,pthread_create在mmap2返回错误的时候调用clone.而在网上搜到资料里fork和vfork调用的是do_fork,但是我通过trace没有跟踪到这个函数,问了个了解内核实现的同学说do_fork调用clone..好吧,不管怎么样都不影响我们对他的理解。

线程和进程在内核的系统调用的相似性上表明两者在linux下的区别,进程由系统内核实现,线程在系统调用之余其建立、销毁、同步由线程库pthread做了大量的工作。

具体的clone函数的参数的说明能更了解一下两者的概念,这里我就不继续往下深挖了。

这个帖子讨论的还很有意义,http://topic.csdn.net/u/20100514/23/a71bad9c-8c84-4e9c-aa7f-c961af943a7c.html

如果了解了线程和进程的内存布局图,对两者的认识可能更清晰一点。(进程笔记那一节我记录了进程的内存布局图)

APUE学习(五):线程与进程(API与概念部分)

这个图出自http://www.kaoyan.com/kaoyan/18/330074/index_6.html,因为他是概念性的介绍,可能各个系统的实现不太一样。但是大体应该也差不多,一个进程内的

多线程共享代码段、数据段(初始化&未初始化),而其堆栈段是不同的(也就是控制流)。

(三) 保留位

windows的进程与线程的关系(虽然之前做windows的开发比较多一些但是还真没有好好理解这一块,汗颜)

牵扯到信号、分离&僵尸、资源清理的一下疑问,以后补充

之前接触多线程实现都是windows下,对linux的线程与进程的认识局限在linux的进程是轻量级进程,在linux下多用多进程进行编程。而现在我的理解是linux下的进程实现确实是比windows快很多,但是其线程实现又比进程实现快很多两者实现我们也略有介绍。所以同步需要比较少 的情况下,不管是windows还是linux采用多线程还是比较好一些。对一下概念做点代码测试能使理解更立体一点:)概念上资源调度的基本单元是进程,控制调度的基本单元是线程,通过本次的代码测试对概念和实现有了新认识

继续阅读