牛商网建设的食品网站,深圳定制建站公司电话,做网站现在什么最赚钱,网站建设选择数据库#x1f308;个人主页#xff1a;Fan_558 #x1f525; 系列专栏#xff1a;Linux #x1f339;关注我#x1f4aa;#x1f3fb;带你学更多操作系统知识 文章目录 前言一、死锁#xff08;1#xff09;死锁概念 二、同步#xff08;1#xff09;同步概念#xff… 个人主页Fan_558 系列专栏Linux 关注我带你学更多操作系统知识 文章目录 前言一、死锁1死锁概念 二、同步1同步概念2条件变量3函数接口4代码实例 小结 前言
本文将会向你介绍死锁的概念以及同步的概念和实现
一、死锁
1死锁概念
死锁是指在一组进程中的各个进程均占有不会释放的资源但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态。 举个例子F1与F2去买奶茶此时F1和F2手中都有5块钱奶茶需要十块钱F1伸手向F2要钱F2不肯并说你把钱给我F1自然也是不愿意的那么他们手中都有五元钱又互相申请对方的五元钱双方都不肯放手 死锁四个必要条件 互斥条件一个资源每次只能被一个执行流使用 请求与保持条件一个执行流因请求资源而阻塞时对已获得的资源保持不放 不剥夺条件:一个执行流已获得的资源在末使用完之前不能强行剥夺 循环等待条件:若干执行流之间形成一种头尾相接的循环 等待资源的关系 避免死锁 破坏死锁的四个必要条件 加锁顺序一致 避免锁未释放的场景 资源一次性分配 Lock申请锁失败线程会阻塞住不会返回trylock是申请锁的非阻塞版本
二、同步
1同步概念 同步在保证数据安全的前提下让线程能够按照某种特定的顺序访问临界资源从而有效避免饥饿问题叫做同步前文我们提到公共独立自习室的例子若一个人长时间持有钥匙当他出门并把钥匙重新放回原处的时候看到一大堆人在等他出来他不想失去这个自习室于是他又进去了他那么轻松再次进去的原因就是他距离钥匙更近些对钥匙的竞争力更大线程也是如此。若是其它线程长时间不能得到共享资源势必会导致饥饿问题 前一篇文章我们也提到定一个规矩出来的人不能立马重新申请锁想要继续申请必须排到队列的最后面外面来的必须排队 2条件变量
要么继续申请锁要么退出不管要干什么做后续工作之前必须把铃铛敲一下 把铃铛和队列称为条件变量提供一种简单的通知机制唤醒线程并提供一个队列 让线程在等待队列中排队
3函数接口
1、初始化条件变量 静态分配
pthread_cond_t condPTHREAD_COND_INITIALIZER注意静态分配的条件变量不需要手动销毁
动态分配
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict
attr);
参数
cond要初始化的条件变量
attrNULL2、利用条件变量等待资源就绪
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数
cond要在这个条件变量上等待
mutex互斥量后面详细解释3、资源就绪后主线程唤醒新线程来访问共享资源
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond)4、销毁
int pthread_cond_destroy(pthread_cond_t *cond)4代码实例
#include iostream
#include unistd.h
#include pthread.h
#include stdint.hint cnt 0;
//初始化锁、条件变量
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond PTHREAD_COND_INITIALIZER;
void* Count(void* args)
{//线程分离pthread_detach(pthread_self());uint64_t number (uint64_t)args;while(true){//加锁pthread_mutex_lock(mutex);//等待pthread_cond_wait(cond, mutex);std::cout pthread: number , cnt: cnt std::endl;//解锁pthread_mutex_unlock(mutex);sleep(3);}
}
int main()
{for(uint64_t i 0; i 5; i){pthread_t tid;//创建线程pthread_create(tid, NULL, Count, (void*)i);}while(true){sleep(1);//唤醒等待队列头部的线程//std::cout Its time to get up: one thread std::endl;//pthread_cond_signal(cond);std::cout Its time to get up: all thread std::endl;pthread_cond_broadcast(cond);}return 0;
}这段代码的逻辑本质是这样
加锁-----------
判断共享资源是否就绪
while(不满足){
等待资源就绪}
执行接下来的代码
code...
...
解锁-----------三个疑问 一、为什么判断条件要放在加锁解锁临界资源里之间 原因 可是我们怎么知道我们要让一个线程去挂起呢一旦调用该接口pthread_cond_wait(cond, mutex)线程就挂起了 一定是临界资源不就绪你怎么知道临界资源是就绪还是不就绪呢 你判断出来的 怎么判断出来的呢 那一定是有访问该临界资源否则怎么知道就绪还是不就绪呢。 那么为了防止多并发问题那么我们是不是应该将会访问临界资源的判断加锁呢 必须是的也就是判断必须在加锁之后 二、为什么pthread_cond_wait也要放在加锁和解锁之间 因为当条件不满足的时候就需要去等待 三、pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex)为什么第二个参数携带锁 因为当一个线程进到临界区内时当资源不就绪该线程就应该去等待可是如果该线程不释放这把锁就去等待的话那么下一个线程该如何进入临界区内呢锁只有一把所以pthread_cond_wait第二个参数传入一把锁的原因是为了让线程去等待前释放锁 答疑完了让我们来看看运行结果如何 每次唤醒一个线程各个线程按照特定的次序访问这批资源 唤醒所有线程
小结
今日的分享就到这里啦如果本文存在疏漏或错误的地方还请您能够指出