Linux多线程 - 基本操作
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多线程 - 基本操作的更多相关文章
- Linux多线程编程初探
Linux线程介绍 进程与线程 典型的UNIX/Linux进程可以看成只有一个控制线程:一个进程在同一时刻只做一件事情.有了多个控制线程后,在程序设计时可以把进程设计成在同一时刻做不止一件事,每个线程 ...
- Linux 多线程 - 线程异步与同步机制
Linux 多线程 - 线程异步与同步机制 I. 同步机制 线程间的同步机制主要包括三个: 互斥锁:以排他的方式,防止共享资源被并发访问:互斥锁为二元变量, 状态为0-开锁.1-上锁;开锁必须由上锁的 ...
- Linux多线程服务端编程一些总结
能接触这本书是因为上一个项目是用c++开发基于Linux的消息服务器,公司没有使用第三方的网络库,卷起袖子就开撸了.个人因为从业经验较短,主 要负责的是业务方面的编码.本着兴趣自己找了这本书.拿到书就 ...
- 《Linux 多线程服务端编程:使用 muduo C++ 网络库》电子版上市
<Linux 多线程服务端编程:使用 muduo C++ 网络库> 电子版已在京东和亚马逊上市销售. 京东购买地址:http://e.jd.com/30149978.html 亚马逊Kin ...
- [转载]赖勇浩:推荐《Linux 多线程服务器端编程》
推荐<Linux 多线程服务器端编程> 赖勇浩(http://laiyonghao.com) 最近,有一位朋友因为工作需要,需要从网游的客户端编程转向服务器端编程,找我推荐一本书.我推荐了 ...
- 《Linux多线程服务端编程:使用muduo C++网络库》上市半年重印两次,总印数达到了9000册
<Linux多线程服务端编程:使用muduo C++网络库>这本书自今年一月上市以来,半年之内已经重印两次(加上首印,一共是三次印刷),总印数达到了9000册,这在技术书里已经算是相当不错 ...
- linux多线程下载工具mwget
linux多线程下载工具mwget 经常使用wget进行文件下载,然而wget的处理速度并不如人意.遇到一些国外的站点,经常慢得像蜗牛一般.然而为了解决这个问题,便有了mwget:m表示multi多线 ...
- Linux多线程实例练习 - pthread_cancel()
Linux多线程实例练习 - pthread_cancel 1.代码 xx_pthread_cancel.c #include <pthread.h> #include <stdio ...
- Linux多线程实例练习 - pthread_exit() 与 pthread_join()
Linux多线程实例练习 - pthread_exit 与 pthread_join pthread_exit():终止当前线程 void pthread_exit(void* retval); pt ...
随机推荐
- httpclient 用法
链接地址 https://www.cnblogs.com/mykcode/p/7833090.html 在程序用调用 Http 接口.请求 http 资源.编写 http 爬虫等的时候都需要在程序集中 ...
- 使用原生方法从kafka消费消息
kafka最早是linkedin开发的一套高性能类队列结构,具有发布—订阅功能.现在是apache的项目之一.支持很多种客户端从其中进行consume,网上也有许多第三方的客户端(注1),但下面我们只 ...
- js判断图片是否加载完毕
附件: https://www.jb51.net/article/102385.htm 问题: .offset().top和$(window).scrollTop()每次刷新页面后滚动的值有时候会不 ...
- LOJ#3087. 「GXOI / GZOI2019」旅行者(最短路)
题面 传送门 题解 以所有的感兴趣的城市为起点,我们正着和反着各跑一边多源最短路.记\(c_{0/1,i}\)分别表示正图/反图中离\(i\)最近的起点,那么对于每条边\((u,v,w)\),如果\( ...
- vue 学前班002(创建一个实例)
创建一个Vue实例 我们之前说过,Vue是数据驱动视图的,只要model(模型层)的数据改变了,Vue就会帮我们改变视图上显示的内容,不用我们自己去动手写代码更新.那么,它是怎么做到的,我们的代码要怎 ...
- 导数、多元函数、梯度、链式法则及 BP 神经网络
一元函数的导数 对于函数\(y=f(x)\),导数可记做\(f'(x_0)\).\(y'|x=x_0\)或\(\frac{dy}{dx}|x=x_0 \).定义如下: \[f'(x_0) = \lim ...
- php 中的查找算法 和 排序方法(多字段排序)
一.查找算法 1.顺序查找(一个一个查,效率低,不用多说) 2.二分查找 /* php 二分查找 在$a数组里查找$x的位置 $a必须是一个以升序排序后的数组 */ function binsearc ...
- leetcode-917-仅仅反转字母
题目描述: 给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转. 示例 1: 输入:"ab-cd" 输出:"dc-b ...
- Rsync备份服务
一.Rsync 原理图 二.Rsync 原理描述 2.1:什么是Rsync Rsync是备份的一款软件,它可以实现全量备份.增量备份,也可以在不改变内容.属性的情况下进行同步备份,端口默认是873 2 ...
- 第7章—SpringMVC高级技术—处理异常
处理异常 处理异常 不管发生什么事情,不管是好的还是坏的,Servlet请求的输出都是一个Servlet响应.如果在请求处理的时候,出现了异常,那它的输出依然会是Servlet响应.异常必须要以某种方 ...