Unix/Linux操作系统-线程同步

一、同步、竞争、互斥


  • 同步:达到某种状态,当多个线程同时访问其共享的资源时,需要相互协调,防止出现数据不一致、不完整的问题。
  • 竞争:有些资源在同一时刻只有一个线程访问,对于这种资源的访问,需要竞争。
  • 互斥:当资源获取到后,能够防止资源被其他线程再次获取的方法交互斥。

二、互斥量


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init (pthread_mutex_t *mutex,pthread_mutexattr_t *mutexattr)

功能:初始化互斥量,使用第二互斥量来初始化第一个互斥量,如果第二个为空,则使用默认参数初始化互斥量,也可以使用宏来初始化。


int pthread_mutex_destroy (pthread_mutex_t *mutex)

功能:销毁互斥量
注意:互斥量是一个结构体,里面有成员是指针,指向了堆内存数据,需要显式初始化函数以及销毁函数。如果使用堆内存存储互斥量,需要在调用了销毁函数后,再进行free。


int pthread_mutex_lock (pthread_mutex_t *mutex)

功能:锁定互斥量,当互斥量是锁定状态,此函数则阻塞(直到互斥量在其它线程中解锁,调用者者线程加锁成功才返回)。
注意:互斥量一旦加锁,只有它自己能解。


int pthread_mutex_trylock (pthread_mutex_t *mutex)

功能:尝试锁定互斥量,能锁就锁,不能锁就返回。


int pthread_mutex_timedlock (pthread_mutex_t *mutex,struct timespec *abstime)

功能:在指定时间内锁定一个互斥量(使用的系统时间)。

struct timespec
{
	time_t tv_sec;        /* Seconds.  */
	long int tv_nsec;       /* Nanoseconds.  */
};

int pthread_mutex_unlock (pthread_mutex_t *mutex)

功能:解锁


三、死锁

  • 死锁:多个线程进行等待对方的资源,在得到所有的资源继续运行前,都不会释放自己的资源,这样造成的循环等待现象。
  • 构成死锁的四大必要条件
    • 资源互斥
    • 占有,还想占有(请求并保持)
    • 资源不可剥夺
    • 环路等待(互相等待)
  • 防止死锁的方法
    • 破坏构成死锁的四大必要条件之一
      • 破坏互斥条件,让资源能够共享(有些资源不能共享,如打印机)
      • 破坏请求并保持状态,采用预分配的方法,程序运行前,一次申请好所需要的所有资源(资源容易浪费)
      • 破坏不可剥夺条件,对已经占用资源的线程发送取消请求,但是实现起来比较困难。
      • 破坏循环等待条件,为每个资源进行编号,采用顺序的资源分配方法,规定每个线程必须按照递增的顺序请求资源,缺点是编号必须相对稳定,增加新资源时会比较麻烦,而且有些特殊的业务逻辑不能完全按照指定的顺序分配资源
  • 避免产生死锁的算法(银行家算法)
    • 产生死锁后无法消除,在产生死锁前,尽量避免产生死锁
      • 贷款的额度不能超过银行现有资金的总和
      • 分批向银行贷款,但是货款额度不能超过最开始最大需求量的总和
      • 银行如果不能满足客户的需要,必须即时给出答复
      • 客户必须在规定时间内还款
  • 如果检测到死锁
    • 画出资源分配图,并简化,模拟资源分配的过程
    • 监控线程或进程的栈内存使用情况
    • 设计看门狗机制(TCP心跳包)

四、信号量

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量(创建信号量)
sem:信号量ID,输出
pshared:一般为0(线程之间)进程中使用的。非零表示进程间使用,但Linux不支持
value:信号量的初始化

int sem_wait(sem_t *sem);
功能:信号量减1,不够减则阻塞(信号量为0时)

int sem_trywait(sem_t *sem);
功能:信号量减1,不够减时立即返回-1

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
功能:信号量减1,不够减则阻塞,直到abs_timeout超时返回-1

int sem_post(sem_t *sem);
功能:信号量+1

int sem_destroy(sem_t *sem);
功能:销毁信号量

int sem_getvalue(sem_t *sem, int *sval);
功能:获取信号量的值

五、生产者与消费者模型

在这里插入图片描述

六、条件变量

  • 条件变量可以让线程在满足特定的条件下暂停(睡眠)。但是必须要在互斥量的配合下使用

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

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

int pthread_cond_wait (pthread_cond_t *cond,pthread_mutex_t *mutex)
功能:让调用者线程进入睡眠,并解锁一个互斥量
cond:线程睡入的条件变量
mutex:线程睡眠前的要解锁的互斥量(是不是锁定状态没有关系)

int pthread_cond_signal (pthread_cond_t *cond)
cond:唤醒条件变量中的1个线程(先睡先醒)
注意:线程醒的前提条件是互斥量必须是解锁状态的,线程醒前会再次加锁,如果不能加锁就不会醒来

int pthread_cond_timedwait (pthread_cond_t *cond,pthread_mutex_t *mutex,struct timespec *abstime)
功能:让调用者线程进入睡眠(指定睡眠时间),并解锁一个互斥量
注意:系统时间

七、哲学家就餐问题

哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
提示:使用条件变量和互斥量实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值