线程基础与死锁

线程

线程介绍:

  • 线程就是进程中负责执行的部分,是进程内部的控制序列,它是轻量级的,没有自己独立的内存资源:代码段,数据段(data,dss)、堆区、环境变量、命令行参数、文件描述符、信号处理函数、当前的工作目录

  • 线程拥有独立的栈内存,也就是它自己独立的局部变量。

  • 一个进程中至少有一个线程,我们把它叫做主线程,也可以再创建多个线程。

注意:进程是一个资源单位,线程是一个执行单位,线程是进程的一部分,进程中正是有了线程才能动起来

POSIX线程

  • 早期各计算机厂商自己私有的线程库,接口实现的差异非常大,不利于开发、不利于移植

  • 世界标准化组织于1995年,指定了统一的线程接口标准,遵循这一标准的线程都被统称为POSIX线程,简称pthread

  • pthread包含一个头文件 pthreah.h 和一个共享库 libpthread.so

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
    功能:创建一个线程
    thread:输出型参数,用于返回新创建线程的ID
    attr:线程属性,一般写NULL即可
    start_routine:线程的入口,相当于主线程的main函数
    arg:传递给线程入口函数的参数
    返回值:成功返回0 失败返回-1  
    
    注意:默认情况下主线程结束,子线程会跟着一起结束 
    注意:从表面上来看,主线程结束后,子线程会跟着结束,但事实情况并不是,子线程之所以结束是因为主线程执行了main函数中隐藏的return语句,导致整个进程退出,所有子线程才结束,如果主线程调用pthread_exit自杀,注意就没有线程执行return语句,进程就不会结束,子线程也不会结束
    
    int pthread_join(pthread_t thread, void **retval);
    功能:等待指定的线程结束,回收其资源,获取返回值
    thread:等待线程的ID
    retval:用于存储线程的返回值 
    
    
    

主线程与子线程传参

  • 创建线程时传参

    把传子线程的数据的内存首地址写在pthread_create函数的最后一个参数。

    是否要进程传参与数据存储在那块内存中无关,与数据的作用域有关

    主线程的局部变量、块变量、字符串字面值

  • 线程的返回值

    返回一个地址,该地址指向一块内存,里面存储着要返回给主线程的数据。

    但该内存不可以是线程的栈内存,因为线程一旦结束它的栈内存会被释放。

一个函数怎么确定它被那个函数调用了

pthread_t pthread_self(void);
功能:获取当前线程的ID

int pthread_equal(pthread_t t1, pthread_t t2);
功能:判断两个线程的ID是否相等
返回值:相等返回真,不同返回假

线程的结束:

  • 从线程入口函数return
  • 调用pthead_exit
void pthread_exit(void *retval);
功能:结束当前线程
retval:返回给pthead_join

注意:如果线程调用exit函数,将结束整个线程

线程的取消操作

一个线程让另一个线程结束,但也要看另一个线程是否同意

int pthread_cancel(pthread_t thread);
功能:让指定线程结束

int pthread_setcancelstate(int state, int *oldstate);
功能:设置当前线程是否能被取消
state:      
    PTHREAD_CANCEL_ENABLE	允许取消
    PTHREAD_CANCEL_DISABLE	禁止取消

oldstate:获取线程旧的取消状态   

int pthread_setcanceltype(int type, int *oldtype);
功能:设置线程的取消类型
type:
    PTHREAD_CANCEL_ENABLE	在合适的时间取消
    PTHREAD_CANCEL_DISABLE	在任何时间取消
oldtype:获取线程旧的取消类型	    

线程分离

  • 主线程创建线程后,它可以等待子线程结束(回收资源)。
  • 当主线程与子线程分离后,子线程可以自己回收资源。
int pthread_detach(pthread_t thread);
功能:与指定的子线程分离,让它自己回收资源
thread:子线程的ID

线程的一些函数,自己回收资源

// 销毁线程属性结构体          // 初始化线程属性结构体
pthread_attr_destroy          pthread_attr_init

// 获取线程栈内存警戒区大小     // 设置线程栈内存警戒区大小
pthread_attr_getguardsize     pthread_attr_setguardsize
    
// 获取线程的调度策略的来源     // 设置线程的调度策略的来源
pthread_attr_getinheritsched  pthread_attr_setinheritsched
PTHREAD_INHERIT_SCHED 默认继承创建者的高度策略
PTHREAD_EXPLICIT_SCHED 根据参数决定(schedpolicy、schedparam才有意义)

// 获取线程的调度策略          // 设置线程的调度策略
pthread_attr_getschedpolicy   pthread_attr_setschedpolicy
SCHED_FIFO,  先进先出策略
SCHED_RR     轮转策略
SCHED_OTHER  普通策略(默认,优先级,schedparam才有意义)

// 获取线程的优先级            // 获取线程的优先级
pthread_attr_getschedparam    pthread_attr_setschedparam

// 获取线程的竞争范围          // 设置线程的竞争范围 
pthread_attr_getscope         pthread_attr_setscope
PTHREAD_SCOPE_SYSTEM:在系统内存竞争
PTHREAD_SCOPE_PROCESS:进程内竞争,但Linux系统不支持该选项

// 获取栈内存的起始地址和大小   // 设置栈内存的起始地址和大小
pthread_attr_getstack         pthread_attr_setstack
    
// 获取栈内存的起始地址        // 设置栈内存的起始地址
pthread_attr_getstackaddr     pthread_attr_setstackaddr
    
// 获取栈内存的大小            // 设置栈内存的大小
pthread_attr_getstacksize     pthread_attr_setstacksize

线程同步

当多个线程同时访问同一个资源时,如果不进行协调可能会产生数据混乱、操作失效等现象,我们需要使用一些特殊的技术来保障线程之间协同工作,这些技术叫做线程同步技术。

互斥量

pthread_mutex_t 互斥锁
int  pthread_mutex_init(pthread_mutex_t  *mutex,  const  pthread_mutex‐attr_t *mutexattr);
功能:初始化互斥量

int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:给互斥量加锁,如果该互斥量已经被加锁,该函数会阻塞

int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:尝试给互斥量加锁,如果不能加则立刻返回

int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:给互斥量解锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁互斥量

休眠

条件变量
pthread_cont_t 能够让线程进入睡眠的对象	//	与互斥量配合使用

int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t*cond_attr);
功能:初始化条件变量

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:让当前线程睡入cond条件变量,并自动解锁
    
int pthread_cond_signal(pthread_cond_t *cond);
功能:叫醒条件变量中的一个线程,线程会从pthread_cond_wait返回,并对互斥量加锁,如果无法成功加锁则继续阻塞

int pthread_cond_broadcast(pthread_cond_t *cond);
功能:叫醒条件变量中的所有线程,条进变量中的线程会从pthread_cond_wait返回,并对互斥量加锁,如果无法成功加锁则继续阻塞

int   pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *abstime);
功能:睡入条件变量,指定的时间后醒来,自动解锁,

int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量

死锁问题

  • 死锁的定义

    多个进程或线程互相等待对方的资源,在得到对方资源之前,都不会释放自己的资源,这种死锁造成循环等待的现象叫死锁

  • 产生死锁的四大必要条件

    a、资源互斥不能共享

    b、占用且等待

    c、资源不可剥夺

    d、环路等待

  • 防止产生死锁的方法

    1、破坏互斥条件,让资源能共享

    ​ 想办法让资源能够共享,解决办法就是增加资源。缺点:如果资源时硬件,可能会有经济上的浪费

    2、破坏请求并保持条件

    ​ 在程序运行前一次性分配它所需要的所有资源,否则不执行。缺点:可能浪费系统资源,有的资源可能短时 间内用不上

    3、破坏不可剥夺的条件

    ​ 请求新的资源失败时,释放旧的资源,过一段时间后再重新获取所有资源。缺点:反复的释放、申请资源可 能会浪费时间

    4、破坏循环等待的条件

    ​ 把所有的资源进行编号,所有的线程按照顺序进行请求资源。缺点:编号必须要稳定,这样就限制了新的资 源加入。

  • 死锁的检测

    1、画出资源的分配简图

    2、简化资源分配图

    3、按照产生死锁的四大条件进行检查,是否有请求环

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值