0. 线程 vs 进程

何为线程?线程即轻量级进程,如何理解轻量级这个概念?

我们知道,Linux的资源分为用户空间资源和内核空间资源:

  • 用户空间资源:用来存放用户自定义的一些数据,用户可直接控制;
  • 内核空间资源:用OS统一调配的资源,用户无权进行控制

1). 用户空间资源



由上图可以看出:

  • 进程

    子进程具备自己独立的用户空间(内容全部复制父进程);

    父子进程不可相互访问对方资源;
  • 线程

    仅申请自己的栈空间,与同进程的其它线程共享内存空间;

    需要注意资源的同步和互斥访问问题

对不同内存空间的解释:

  • 栈(stack):

    存放程序的局部变量(不包括static修饰的变量);

    后入先出(LIFO),
  • 堆(Heap):

    用于存放进程运行中被动态分配的内存段;

    调用malloc/new()分配,free/delete()释放
  • BSS区:Block Started by Symbol

    属于静态内存分配, 存放程序中为初始化的全局变量
  • 全局变量区

    静态(static)全局变量 和 静态(static)局部变量
  • 代码段:只读

    存放程序的执行代码,有时也存储一些只读的常数变量(如字符串常量等)

下图是以32位系统为例进行介绍的(系统内核占用高地址1GB内存)



(该图转自:C程序(进程)的内存布局)

2). 内核空间资源

创建线程时,内核仍旧创建一个新的PCB来标识这个线程;因此从内核角度看,进程和线程时一样的。

进程是OS管理资源的基本单元,线程时OS系统调用的基本单元

1. 线程基本操作

功能 进程 线程
创建 fork() pthread_create()
退出 exit pthread_exit()
等待 wait/waitpid() pthread_join()
取消 abort() pthread_cancel()
获取ID getpid() pthread_self()
调度策略 SCHED_OTHER、SCHED_FIFO、SCHED_RR SCHED_OTHER、SCHED_FIFO、SCHED_RR
通信机制 管道、消息队列、共享内存、信号、信号量 信号、信号量、互斥锁、读写锁、条件变量

1). 创建线程 - pthread_create()

  • 作用

    创建新的线程

  • 头文件

      #include <pthread.h>
  • 函数原型

      int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
  • 参数

  • thread: 存放线程ID

         typedef unsigned long int pthread_t;
  • attr:设置线程属性,一般为NULL

  • start_routine: 线程执行哪段代码

  • arg: 运行函数的参数地址,若需传入多个参数,则需要使用包含这些参数的结构体地址

  • 返回值

    成功:0

    失败:非零值

关于线程的属性

  线程的属性主要围绕其所能申请的资源,用户能够显示管理的线程的属性主要为栈空间信息,如下结构体:

typedef struct
{
int detachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
}pthread_attr_t;

详细的属性操作请参考:http://blog.csdn.net/scanery/article/details/7242768

2). 获取线程id - pthread_self()/pthread_gettid()

  • 进的pid: 每个进程都有自己独一无二的pid_t pid, 由getpid()函数获得;
  • 线程id
  • 用户空间

    pthread_t pid,由ptread_self()函数获得;该id由线程库维护,其id空间是相对独立的(即不同进程的子线程pid有可能相同);实际上,该id是当前线程的description地址;
  • 内核空间

    从内核中看,每个线程都具有自己独一无二的tid(但是不能通过ps看,也不会在/proc下生成对应编号的目录),只能通过Linux的系统调用syscall(SYS_getpid)来获取

①. pthread_self()

  • 作用

    获取调用者的线程ID:pthread_id

  • 头文件

      #include <pthread.h>
  • 函数原型

      pthread_t pthread_self(void)
  • 参数

  • 返回值

    成功: 线程ID,同pthread_creat()的pid相同

    失败:总是成功

②. syscall()

  • 作用

    调用没有glibc实现的函数,使其可以进入内核态

  • 头文件

      #include <sys/syscall.h>
  • 函数原型

      int syscall(int number, ...)
  • 参数

  • number:

    系统调用号,详细参见 `usr/include/bits/syscall.h>
  • ...:

    number的参数值
  • 返回值

    成功: 根据参数的不同进行返回(一般为0)

    失败:-1

③. gettid()

  • 作用

    获取线程的真是tid

  • 头文件

      #include <sys/types.h>
  • 函数原型

      pid_t gettid(void)
  • 参数

  • 返回值

    成功:0

    失败:无失败

3). 线程等待/退出 - pthread_join()/pthread_exit()

①. pthread_exit()

  • 作用

    退出当前线程

  • 头文件

      #include <pthread.h>
  • 函数原型

       void pthread_exit(void *retval)
  • 参数

  • retval:

    退出时线程的状态
  • 返回值

    无返回值

②. pthread_join()

  • 作用

    等待子线程结束

  • 头文件

      #include <pthread.h>
  • 函数原型

      int pthread_join(pthread_t thread, void **retval)
  • 参数

  • thread:

    等待线程的tid
  • retval:

    子线程退出时的返回状态
  • 返回值

    成功: 0

    失败: 非零值

③. pthread_cleanup_push()/pthread_cleanup_pop()

  • 作用

    线程退出前执行用户定义的操作

  • 头文件

      #include <phtread.h>
  • 函数原型

      void pthread_cleanup_push(void (*routine)(void *), void *arg)
    void pthread_cleanup_pop(int execute)
  • 参数

  • (void (routine)(void)): 压入栈顶的函数
  • arg:压入函数的参数
  • execute: 弹出某函数时是否执行,0为不执行,非零为执行
  • 返回值

4). 取消线程

①. pthread_cancel()

  • 作用

    取消正在执行的线程

  • 头文件

      #include <phtread.h>
  • 函数原型

      int pthread_cancel(pthread_t thread)
  • 参数

  • thred: 欲取消的线程ID
  • 返回值

    成功: 0

    失败:非0

② pthread_setcancelstate() / pthread_setcaneltype()

  • 作用

    取消正在执行的线程

  • 头文件

      #include <phtread.h>
  • 函数原型

      int pthread_setcancelstate(int state, int *oldstate)
    int pthread_setcanceltype(int type, int *oldtype)
  • 参数

  • state: 欲设置的线程状态
  • oldstate: 存储原来的线程状态
线程状态 说明
PTHREAD_CANCEL_ENABLE 默认值,该线程可被取消
PTHREAD_CANCEL_DISABLE 不可被取消
  • type: 欲设置的类型
  • oldtype: 存储原来的类型
线程类型 说明
PTHREAD_CANCEL_DEFERRED 在取消点取消
PTHREAD_CANCEL_ASYNCHRONOUS 可随时执行新的或未决的请求
  • 返回值

    成功: 0

    失败:非0

Linux多线程 - 基本操作的更多相关文章

  1. Linux多线程编程初探

    Linux线程介绍 进程与线程 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情.有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程 ...

  2. Linux 多线程 - 线程异步与同步机制

    Linux 多线程 - 线程异步与同步机制 I. 同步机制 线程间的同步机制主要包括三个: 互斥锁:以排他的方式,防止共享资源被并发访问:互斥锁为二元变量, 状态为0-开锁.1-上锁;开锁必须由上锁的 ...

  3. Linux多线程服务端编程一些总结

    能接触这本书是因为上一个项目是用c++开发基于Linux的消息服务器,公司没有使用第三方的网络库,卷起袖子就开撸了.个人因为从业经验较短,主 要负责的是业务方面的编码.本着兴趣自己找了这本书.拿到书就 ...

  4. 《Linux 多线程服务端编程:使用 muduo C++ 网络库》电子版上市

    <Linux 多线程服务端编程:使用 muduo C++ 网络库> 电子版已在京东和亚马逊上市销售. 京东购买地址:http://e.jd.com/30149978.html 亚马逊Kin ...

  5. [转载]赖勇浩:推荐《Linux 多线程服务器端编程》

    推荐<Linux 多线程服务器端编程> 赖勇浩(http://laiyonghao.com) 最近,有一位朋友因为工作需要,需要从网游的客户端编程转向服务器端编程,找我推荐一本书.我推荐了 ...

  6. 《Linux多线程服务端编程:使用muduo C++网络库》上市半年重印两次,总印数达到了9000册

    <Linux多线程服务端编程:使用muduo C++网络库>这本书自今年一月上市以来,半年之内已经重印两次(加上首印,一共是三次印刷),总印数达到了9000册,这在技术书里已经算是相当不错 ...

  7. linux多线程下载工具mwget

    linux多线程下载工具mwget 经常使用wget进行文件下载,然而wget的处理速度并不如人意.遇到一些国外的站点,经常慢得像蜗牛一般.然而为了解决这个问题,便有了mwget:m表示multi多线 ...

  8. Linux多线程实例练习 - pthread_cancel()

    Linux多线程实例练习 - pthread_cancel 1.代码 xx_pthread_cancel.c #include <pthread.h> #include <stdio ...

  9. Linux多线程实例练习 - pthread_exit() 与 pthread_join()

    Linux多线程实例练习 - pthread_exit 与 pthread_join pthread_exit():终止当前线程 void pthread_exit(void* retval); pt ...

随机推荐

  1. ActiveMq 配置多队列

    一直在赶项目,好久没有写博文了,中间偶尔有些代码什么的,也都是放到github了,不过大多都是测试代码,毕竟有些成型的东西是给公司写的,鉴于职业道德,还是不好公开. 言归正传,这两天在接入第三方的收费 ...

  2. 关于Git bash 在win10重装系统情况下闪退并生成mintty.exe.stackdump文件的问题

    问题内容:在重装win10系统情况下,有可能会出现安装Git后右击Git bash会出现闪退并生成mintty.exe.stackdump文件 个人解决方案:查看网络上各位网友的意见和解决方法后,自己 ...

  3. 开源且功能强大的C# 扩展方法类库Pure.Ext,包含1000+个拓展方法 (支持.Net Framework和.Net Core)

    先上地址 Github: https://github.com/purestackorg/pure.ext Gitee: https://gitee.com/purestack/pure.ext 扩展 ...

  4. C# 一些代码小结--串口操作

    串口解析显示中文 private String SerialPortReadStr() { try { String str = null; int n = serialPort1.BytesToRe ...

  5. ! [rejected] master -> master (non-fast-forward)

    当向GitHub远程仓库提交请求时,常会出现  ! [rejected]  master -> master (non-fast-forward) 错误. 出现这种错误通常是由于远程仓库的文件版 ...

  6. WPF 获取表格里面的内容

    DataRowView dataRow = DataGridCase.SelectedItem as DataRowView; 代码转为数组分别获取.

  7. WPF点滴(2) 创建单实例应用程序

    最近有同事问道在应用程序启动之后,再次双击应用程序,如何保证不再启动新的应用程序,而是弹出之前已经启动的进程,本质上这就是创建一个单实例的WPF应用程序.在VS的工程树中有一个App.xaml和App ...

  8. js事件处理

    1.js中常用的事件处理程序(event Handler) onabort 用户终止了页面的加载 onblur 用户离开了对象 onchange 用户修改了对象 onclick 用户点击了对象 one ...

  9. Day 7 深copy和浅Copy

    dict.fromkeys的用法 1 2 3 4 5 6 7 8 9 10 11 #dict.fromkeys的用法 #例子1 dic = dict.fromkeys([1,2,3],[]) prin ...

  10. Python 获取主机名

    import socket print socket.gethostname()