【1】线程
- –》 进程是资源分配的最小单位,线程是cpu调度的最小单位
-
概念:线程指的是共享相同地址空间的多个任务
-
特点:
- 由于进程的地址空间是私有的,因此在进程间
上下文切换时,系统开销比较大 - 为了提高系统的性能,许多操作系统规范里引
入了轻量级进程的概念,也被称为线程 - 在同一个进程中创建的线程共享该进程的地址空间
- Linux里同样用task_struct来描述一个线程。
线程和进程都参与统一的调度
- 由于进程的地址空间是私有的,因此在进程间
-
优点:
- 使用多线程的好处大大提高了任务切换的效率
- 多线程通信简单,可以通过全局变量
-
线程和进程的区别:
- 进程间资源相互独立,而同一个进程内的线程间
共享进程内所有的资源 - 多线程间通信简单,但是需要对临界资源
进行互斥与同步操作,多进程间通信较难 - 多线程安全性差,因为其中一个线程崩溃
可能会对其他线程造成影响,多进程间相互独立,
安全性高。
- 进程间资源相互独立,而同一个进程内的线程间
安装:第三方库的man手册
sudo apt-get install manpages-posix manpages-posix-dev
man pthread_create
-
pthread_create
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:创建线程
参数:
thread
:线程tid
attr
:设置属性 NULL
start_routine
:函数指针(线程函数)
void *fun(void *arg)
arg
:给线程函数传参的 -
等待线程结束:
int pthread_join(pthread_t thread, void **value_ptr)
功能:用于阻塞等待一个指定的线程结束
参数:thread
:创建的线程对象
value_ptr
:指针*value_ptr指向线程返回的参数
返回值:成功 : 0
失败:errno -
线程退出函数:
int pthread_exit(void *value_ptr) //return (void *)
功能:用于退出线程的执行
参数:value_ptr
:线程退出时返回的值
返回值:成功 : 0
失败:errno -
获取线程
tid
类似getpid
pthread_t pthread_self(void);
-
控制线程
#include <pthread.h>
int pthread_cancel(pthread_t thread);
*功能: 在线程中发送关闭指定线程的请求
*参数:@thread 线程号
*返回值: 成功: 0- 失败: 负数,更新 errno
-
int pthread_detach(pthread_t thread);
(使线程处于游离态)
设置线程为detach
,这样线程退出资源自动释放,
无需使用pthread_join
//与pthread_join
不同的是不阻塞等待,子线程结束后自动回收,
不影响我主线程的执行。
//datach
不能接受退出进程的返回值
-
面试题:
你对进程和线程的理解
1、共性:二者都为操作系统提供了并发执行能力
2、区别:
调度和资源分配:线程是参与内核调度最小基本单位,进程是拥有资源的最小单位
地址空间:进程间相互独立,而同一进程内的线程间共享进程内所有资源
通信:多线程间通信简单,但是需要对临界资源进行互斥与同步操作,多进程间通信较难。
安全:多线程安全性差,因为其中一个线程崩溃可能会对其它线程造成影响,多进程间相互独立,安全当编译报如下错误,说明编译时没加-lpthread
linux@ubuntu:~/19072/IO/day4$ gcc 2-pthread.c /tmp/cczE0Iiz.o: In
function `main’: 2-pthread.c:(.text+0x3d): undefined reference to
pthread_create collect2: ld returned 1 exit status
【2】同步
优点:线程间很容易进行通信,通过全局变量实现数据共享和交换
缺点:多个线程同时访问共享对象时需要引入同步和互斥机制
- 什么是同步?
同步(synchronization)指的是多个任务(线程)
按照约定的顺序相互配合完成一件事情 - 同步机制:信号量
- 信号量代表某一类资源,其值表示系统中该资源的数量
- 信号量是一个受保护的变量,只能通过三种操作来访问
初始化 sem_init
P操作(申请资源) sem_wait
V操作(释放资源) sem_post - 信号量的值为非负整数 (>=0)
P(S) 含义如下:
if(信号量的值大于0)
{
申请资源的任务继续运行;
信号量的值减一;
}
else
{
申请资源的任务阻塞;
}
V(S) 含义如下:
if(没有任务在等待该资源)
{
信号量的值加一;
}
else
{
唤醒第一个等待的任务,让其继续运行
}
3.相关函数:int sem_init(sem_t *sem, int pshared, unsigned int value)
功能:初始化信号量
参数:sem
:初始化的信号量对象
pshared
:信号量共享的范围(0: 线程间使用
非0:1进程间使用)
value
:信号量初值 >=0 (资源量)
返回值:成功 0
失败 -1int sem_wait(sem_t *sem)
功能:申请资源 P操作 //申请一次资源 ,资源量减1
参数:sem
:信号量对象
返回值:成功 0
失败 -1
3.int sem_post(sem_t *sem)
功能:释放资源 V操作//释放一次资源 ,资源量加1
参数:sem
:信号量对象
返回值:成功 0
失败 -1
【3】互斥
- 概念:
引入互斥(mutual exclusion
)锁的目的是用来保证
共享数据操作的完整性。互斥锁主要用来保护临界资源
每个临界资源都由一个互斥锁来保护,某一资源同时
只允许一个线程对其进行访问。
线程必须先获得互斥锁才能访问临界资源,
访问完资源后释放该锁。如果无法获得锁,
线程会阻塞直到获得锁为止 - 相关函数:
-
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
功能:初始化互斥锁
参数:mutex
:互斥锁
attr
: 互斥锁属性 // NULL表示缺省属性
返回值:成功 0
失败 -1
宏初始化:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
int pthread_mutex_destroy(pthread_mutex_t *mutex)
功能:销毁互斥锁
参数:mutex:互斥锁 -
int pthread_mutex_lock(pthread_mutex_t *mutex)
功能:申请互斥锁
参数:mutex:互斥锁
返回值:成功 0
失败 -1 -
int pthread_mutex_unlock(pthread_mutex_t *mutex)
功能:释放互斥锁
参数:mutex
:互斥锁
返回值:成功 0
失败 -1
-
- 死锁
- 什么是死锁?
死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打
印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的
输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。 - 产生原因:
- 系统资源的竞争
系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。 - 进程运行推进顺序不合适
进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。
- 系统资源的竞争
- 死锁产生的四个条件:
- 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。
此时若有其他进程请求该资源,则请求进程只能等待。 - 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,
此时请求进程被阻塞,但对自己已获得的资源保持不放。 - 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的
进程自己来释放(只能是主动释放)。 - 循环等待条件: 若干进程间形成首尾相接循环等待资源的关系
- 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。
- 如何避免死锁
我们可以通过破坏死锁产生的4个必要条件来 预防死锁,由于资源互斥是资源使用的固有特性是无法改变的。- 破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将
被隐式的释放重新加入到 系统的资源列表中,可以被其他的进程使用,而等待的进程只有重新获得自己原有的
资源以及新申请的资源才可以重新启动,执行。 - 破坏”请求与保持条件“:第一种方法静态分配即每个进程在开始执行时就申请他所需要的全部资源。
第二种是动态分配即每个进程在申请所需要的资源时他本身不占用系统资源。 - 破坏“循环等待”条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的,
稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个进程只有获得较小编号的进程才能申
- 破坏“不可剥夺”条件:一个进程不能获得所需要的全部资源时便处于等待状态,等待期间他占有的资源将
- 什么是死锁?
【4】条件变量
一般与互斥锁搭配使用,可以实现同步机制
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化条件变量
参数:cond:是一个指向结构pthread_cond_t的指针
restrict attr:是一个指向结构pthread_condattr_t的指针,一般设为NULL
返回值:成功:0 失败:非0
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
功能:无条件等待信号的产生
参数:restrict cond:要等待的条件
restrict mutex:对应的锁
返回值:成功:0,失败:不为0
1.解锁
2.阻塞线程
3.唤醒时,上锁
int pthread_cond_signal(pthread_cond_t *cond);
功能:给条件变量发送信号
//唤醒一个阻塞在pthread_cond_wait函数上的线程
参数:cond:条件变量值
返回值:成功:0,失败:非0
int pthread_cond_destroy(pthread_cond_t *cond);
功能:将条件变量销毁
参数:cond:条件变量值
返回值:成功:0, 失败:非0
int pthread_cond_broadcast(pthread_cond_t *cond);
功能: 唤醒全部阻塞在条件变量上的线程
参数: @cond 条件变量地址
返回值: 成功: 0
失败: errno值