线程(二)————线程同步与互斥


title: 线程(二)————线程同步与互斥
date: 2019-08-11 16:08:18
tags: [Linux,线程]
categories: Linux

1、线程的同步与互斥

        同步机制: 多个进程或线程按照一定的先后顺序来执行 。 一般使用pv操作 针对的对象是 信号量

        互斥机制: 主要能够对临界资源进行保护,(保护临资源的完整性 )临界 资源可以是一小段的代码片段 ,保证同一时刻 只能有一个进程来运行被保护的代码片段。 互斥机制 一般是加互斥锁。

2、互斥锁(也称互斥量)

        在 Posix Thread 中定义了一套专门用于线程互斥的 mutex 函数。 mutex 是一种简单的加锁的方法来控制对共享资源的存取,这个互斥锁只有两种状态(上锁和解锁),可以把互斥锁看作某种意义上的全局变量。为什么需要加锁,就是因为多个线程共用进程的资源,要访问的是公共区间时(全局变量),当一个线程访问的时候,需要加上锁以防止另外的线程对它进行访问,以实现资源的独占。在一个时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程才能够对共享资源进行操作。若其他线程希望上锁一个已经上锁了的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。

  • 锁机制保护 临界资源 的完整性

  • 当锁机制被触发的时候,其余线程会被挂起 ,直到锁被释放掉 会解除挂起状态 。

3、初始化(创建)锁

pthread_mutex_t +变量名;

函数原型int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
功能动态的初始化一般锁 ------常用
参数restrict mutex:申请的锁,一般会定义成全局性的变量。锁变量的地址
attr:关于锁的属性 ,可以给NULL 表示默认属性 。
返回值成功:0
失败:返回错误号

互斥锁的属性(第二个参数)有三个值可以选择:

①、PTHREAD_MUTEX_TIMED_NP,这是缺省值(直接写NULL),也就是普通锁(或快速锁)。当一个线程加锁以后,其余请求锁的线程将形成一个阻塞等待队列,并在解锁后按优先级获得解锁。这种锁策略保证了资源分配的公平性。

②、PTHREAD_MUTEX_RECURSIVE_NP,嵌套锁(递归锁),允许同一线程对同一个锁成功获得多次,并通过多次unclock解锁。如果是不同的线程请求,则在加锁线程解锁时重新竞争。

③、PTHREAD_MUTEX_ERRORCHECK_NP,检错锁,如果同一个进程请求同一个锁,则返回EDEADLK,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时不会出现最简单情况下的死锁。

pthread_mutex_t的初始化pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
功能静态的方式 来申请并初始化一把锁 。

4、加锁

        操作共享数据之前加锁、加锁的临界区域尽可能的小。

函数原型int pthread_mutex_lock(pthread_mutex_t *mutex);
参数mutex:要加的锁。阻塞的锁定互斥锁。
要加的锁没有被锁:当前进程将其上锁
被上锁了:阻塞等待该锁被解锁,线程解除阻塞。再将其加锁.

        以下函数不怎么使用

函数原型int pthread_mutex_trylock(pthread_mutex_t *mutex);
参数mutex:要加的锁。非阻塞的锁定互斥锁。
要加的锁没有被锁:当前进程将其上锁
被上锁了:不会阻塞,返回0:尝试加锁成功;返回-1:不会阻塞做其他事
函数原型int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr)
功能与上面函数无差别,只是多了个等待时间参数

5、解锁

函数原型int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数mutex:要解的锁

6、销毁锁

函数原型int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数要销毁的锁

7、死锁

        死锁:是指两个或两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程(线程)在无外力协助下,永远分配不到必须的资源而无法继续运行,这就产生了一种特殊现象死锁。

案例:不加锁

两个线程共同执行fun函数,不加锁的情况下。线程1和线程2共同抢占fun函数,就会出现下面的结果

在这里插入图片描述

案例:在上面的基础上加上锁

加锁以后线程1执行fun时被加锁,线程2再来执行fun时会被阻塞,直到线程1执行完毕,解锁线程2才能执行fun

在这里插入图片描述

8、原子操作

        原子操作(atomic operation)意为“不可被中断的一个或一系列操作”。假设有一片段代码,进程1运行到这段代码的中间时CPU被其他进程2抢走了。其他进程2在获得CPU使用权时有可能对这片代码段进行操作,而我们希望进程1执行完才能让其他进程执行。因此我们可以在这段代码前加上互斥锁,当进程1执行到这段代码时上锁,即使未执行完失去CPU使用权,其他进程也不能对这片代码段进程操作。当进程1再次获取CPU使用权后执行这段代码,解锁后其他进程才能访问这段代码。这样的操作称为原子操作。

9、读写锁

        它是一把锁,称为读写锁。只是读/写时加锁的函数不一样。类型为pthread_rwlock_t lock;类型

        读写锁的特性:

  • 线程A加读锁成功,又来了三个线程,做读操作,可以加锁成功
  • 线程A加写锁成功,又来了三个线程,做读操作,三个线程被阻塞
  • 读写不能同时进行、写的优先级高。

读时共享、写时独占、写优先级高

pthread_rwlock_init        //读写锁的初始化
pthread_rwlock_destroy     //销毁读写锁
pthread_rwlock_rdlock      //加读锁
pthread_rwlock_wrlock      //加写锁
pthread_rwlock_tryrdlock   //尝试加读锁
pthread_rwlock_trywrlock   //尝试加写锁
pthread_rwlock_unlock      //解锁

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值