dedecms医院网站wap模板(橙色),成都注册公司代理公司,莱州网络建站,如何进行网站开发一、互斥锁
1、CPU 运算过程
执行完整个语句后#xff0c;才会把数据写入内存#xff1b;如果执行时被中断#xff0c;那么数据和上下文就会保存到线程的 TCB#xff0c;但数据并不会被写入内存。
1.1. 当 CPU 执行完整个语句时 CPU 最终执行完整个语句的过程 就用上图举…一、互斥锁
1、CPU 运算过程
执行完整个语句后才会把数据写入内存如果执行时被中断那么数据和上下文就会保存到线程的 TCB但数据并不会被写入内存。
1.1. 当 CPU 执行完整个语句时 CPU 最终执行完整个语句的过程 就用上图举个例子。 CPU 是如何执行 a-- 这个句代码的呢
第一步CPU 将内存中变量 a 的值100拷贝到运算器中。第二步在运算器中减一。第三步把新的值99拷回变量 a 里。
1.2. 当 CPU 还未执行完这个语句线程就被换出时 CPU 执行完减 1 操作线程就被换出了 以上图为例CPU 刚执行完减 1 操作线程就被换出。遇到这种没执行完语句的情况CPU 会把计算数据和该线程执行的上下文即该线程执行到哪一行代码拷到该线程的 TCB 里然后再为下一个线程服务。
2、解决方案——互斥锁mutex
2.0. 什么是互斥问题
当多个线程并发执行并访问同一个变量时就会很容易发生变量的一致性问题。
如图所示假如我想让变量 a 从 100 减到 0.
线程 1 在做完 a-- 操作后就被换出了 线程 1 被换出 线程 2 正常执行完整个减 1 操作并重复了很多次直到减到 10被换出线程 1 进来了 线程2被换出 线程 1 执行 而此时 a 这个全局变量又从 10 变成 100 了。
所以这个变量从始至终都只能被一个执行流线程访问。
2.1. 互斥锁原理
下面这是线程申请锁和释放锁的汇编代码
lock: // 申请锁movb $0, %alxchgb %al, mutexif (al 寄存器的内容 0) return 0; // 申请锁成功else 挂起等待;goto lock;unlock: // 释放锁movb $1, mutex唤醒等待 Mutex 的线程return 0; lock 部分的汇编代码的前 2 行的执行过程 但是如果当该线程执行完第一句后就被换出了那么该线程会把 al 寄存器的值和上下文保存到 TCB然后再被换出然后第二个线程再进来从上次的上下文开始接着执行。所以其实申请锁的本质就是看哪个线程拿到 1拿到 1 的那个线程就申请到锁了。
2.2. 相关函数
2.2.1. pthread_mutex_t 类型
就是互斥锁的类型。
2.2.2. pthread_mutex_lock 函数 这个函数用于申请互斥锁。注意这里只是把锁加上而已并不会创建锁。
2.2.3. pthread_mutex_unlock 函数 这个函数用于释放锁。注意这里只是把锁解开了锁还在。
2.2.4. 初始化全局的锁
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER
2.2.5. 初始化局部变量的锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);参数
mutex要初始化的互斥锁
attrnullptr 2.2.6. 销毁互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex)
这个函数是直接让锁消失。 注意 如果创建的锁是用宏创建的就不能掉这个函数。 一定要在解开锁了之后才能调用这个函数。确保后面没有线程用到这个锁。 2.3. 临界区
处于 pthread_mutex_lock 函数和 pthread_mutex_unlock 函数之间的区域就是临界区。
2.4. 临界资源
多线程执行流共享的资源就叫做临界资源。不过临界资源都是每次只能让一个一个线程访问的。但是当线程申请锁时那么锁也是共享资源所以申请锁和释放锁本来就被汇编语言设计成原子性的即只用一句汇编实现。
二、死锁
1、产生死锁的必要条件
互斥条件一个资源每次只能被一个执行流使用。请求和保持条件一个执行流因请求资源而阻塞时它同时也持有已有的资源且不释放。不剥夺条件如果申请不到资源只能等待不能强行抢占。循环条件执行流之间形成有环的等待资源的关系。
2、如何解决
破坏上面的 4 条必要条件的其中一条。资源一次性分配。加锁顺序一致。避免未释放的场景。
三、同步问题
1、什么是同步
同步就是让线程按照一定顺序获取资源而不是一窝蜂地去抢。举个例子假如厕所是一个共享资源一次只能一个人用。当有人进去后就会有很多人在外面等。如果不同步的话一旦厕所里的那个人出来全部人就会一窝蜂地去抢厕所而如果刚出来的那个人的抢占能力非常强那么厕所就会一直被抢占能力最强的那个人占用因为这个人可以出来后再抢。于是就会导致其他人长时间没得上厕所进而引发其他人的饥饿问题。
因此解决方法就是让所有人排队一个个上厕所。从厕所出来的人无论抢占能力强还是弱都要去队尾排队。这种让人们有序地使用厕所就是同步。而把线程看成人那就就是线程的同步了。所以总结来说在保证数据安全的前提下让线程能够按照某种特定的顺序访问临界资源从而有效避免饥饿问题叫做同步。 2、条件变量
2.1. 什么是条件变量
还记得前面厕所排队的例子吗条件变量就是这个等待队列的头节点当申请到资源时线程就会从等待队列出来然后访问共享资源而如果线程没申请到资源时该线程就会进入以条件变量为头节点的等待队列里。 2.2. 相关函数
2.2.0. pthread_cond_t 类型
该类型为条件变量类型。
2.2.1. 初始化全局的条件变量
pthread_cond_t global_cond PTHREAD_COND_INITIALIZER;
2.2.1. 初始化局部变量的条件变量 参数介绍 cond条件变量的地址。attr 条件变量的性质。 这个函数用于初始化条件变量。其实就是初始化等待队列的头节点。
2.2.2. pthread_cond_destroy 函数 参数介绍 cond传条件变量的地址。 注意 如果创建的条件变量是用宏创建的就不能掉这个函数。 这个函数用于释放条件变量。其实就是初始化等待队列的头节点。
2.2.3. pthread_cond_wait 函数 参数介绍 cond传条件变量的地址。 mutex传互斥锁的地址。 此函数用于把线程加入等待队列。如果此时没申请到共享资源该线程就会进入以条件变量为头节点的等待队列里。
2.2.4. pthread_cond_signal 函数 参数介绍 cond条件变量地址。 此函数用于唤醒线程。 即当线程申请到共享资源时这个函数就能让一个线程的 TCB 退出以条件变量为头节点的等待队列。
2.2.5. pthread_cond_broadcast 函数 参数介绍 cond条件变量地址。 即当线程申请到共享资源时这个函数就能让所有线程的 TCB 退出以条件变量为头节点的等待队列。
四、应用生产者消费者问题cp 问题
1、什么是生产者消费者问题
简单来说前提就是生产者和消费者之间有一个共享资源共享内存生产者负责向共享内存放数据消费者负责从共享内存里拿数据。然后我们通过一定的策略解决它们的互斥与同步问题。
2、3 种关系
2.1. 生产者与生产者
生产者与生产者之间是竞争关系因此生产者与生产者之间是互斥关系。
2.2. 生产者与消费者
2.2.1. 互斥关系
因为要保证公共资源的安全性因此要让生产者与消费者处于互斥关系每次只能有一个线程访问共享资源。
2.2.2. 同步关系
因为共享内存里先有数据消费者才可以拿数据。而生产者是负责向内存放数据的。因此先有生产者向共享内存放数据才有消费者从共享内存拿数据这是一种顺序访问共享内存因此生产者与消费者也处于同步关系。
2.3. 消费者与消费者
消费者与消费者之间是竞争关系因此生产者与生产者之间是互斥关系。