当前位置: 首页 > news >正文

迪庆藏族自治州网站建设_网站建设公司_React_seo优化

陕西购物商城网站建设,沧州商贸行业网站建设,apk开发,sae 部署wordpress#x1f525;#x1f525; 欢迎来到小林的博客#xff01;#xff01;       #x1f6f0;️博客主页#xff1a;✈️林 子       #x1f6f0;️博客专栏#xff1a;✈️ Linux       #x1f6f0;️社区 :✈️ 进步学堂       #x1f6f0…         欢迎来到小林的博客       ️博客主页✈️林 子       ️博客专栏✈️ Linux       ️社区 :✈️ 进步学堂       ️欢迎关注点赞收藏✍️留言 这里写目录标题 线程安全互斥锁的使用全局锁的使用局部锁的使用 互斥锁的原理竞争锁的过程释放锁的过程 线程安全 在多线程情况下如果有临界资源且没有保护临界资源的情况下。线程是不安全的。因为CPU的调度机制是随机的而不是等你一个线程执行完才去执行另一个线程。可能在你这个线程执行到一半时又切换到了另一个线程执行。 我们可以用下面这段代码来验证 #includeiostream #includepthread.h #includeunistd.h#define THREAD_MAX_NUM 5int tickets 10000;void* ThreadRun(void* args) {int id *(int*)args;delete (int*)args;//抢票逻辑while(1){if(tickets 0){usleep(1000);//延迟1000微秒tickets--; printf(thread %d 抢了一张票。还剩 %d 张票\n,id,tickets);}else break;}return nullptr; }int main() {pthread_t tids[THREAD_MAX_NUM];for(int i 0 ; i THREAD_MAX_NUM ; i){int* id new int(i1);pthread_create(tidsi , nullptr,ThreadRun,(void*)id);}for(int i 0 ; i THREAD_MAX_NUM ; i){pthread_join(tids[i],nullptr);}return 0; } 这段代码的逻辑就是创建5个线程主线程等待5个线程。然后派这5个线程去抢10000张票(全局变量tickets)。 当票没了的时候跳出循环退出线程。 我们来看看运行结果 第一次测试 第二次测试 第三次测试 我们可以发现三次测试结果。每次最后抢票都抢到了负数。这是非常危险的如果在实际应用中你只有100张票却卖了105张。那么就会有5个用户没有座位这影响是非常严重的。所以说这个线程是不安全的。 为什么会这样呢 我假设有2个线程线程A和线程B。线程A先执行抢票因为抢票的 tickets–并不是原子的。这条语句实际上是由三条汇编语句组成。 分别是: CPU加载tickets - CPU对tickets进行减操作 - CPU把tickets写回到内存。 而在这三个步骤中。如果在第二步完成还没有走到第三步的时候。切换到了另一个线程B执行这段代码线程B抢了5000票后CPU又切到了线程A。并恢复线程A的上下文。可是在线程A的上下文中tickets是9999。随后线程A又把9999写回到内存。 所以线程B明明已经抢了5000张票又被线程A改回到了9999。这是非常非常不安全的。 如何保证线程安全呢 我们只要让临界资源每次只能被一个执行流访问即可。即使是CPU调度切换那么也要把没有访问权限的线程卡在临界资源之外。直到有访问权限的线程访问完临界资源之后。其他线程才能重新争夺这个访问权限。而这个访问权限我们称它为锁 互斥锁的使用 我们可以用互斥锁来保护一段区域这段区域被称为临界区 。 临界区的资源每次只能被一个执行流访问 而互斥锁是一个pthread_mutex_t 类型的变量。 通过pthread_mutex_init函数初始化pthread_mutex_destroy销毁。 pthread_mutex_t mtx; //创建锁变量int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);//锁的初始化返回0为成功。传入锁的地址和锁的属性int pthread_mutex_destroy(pthread_mutex_t *mutex); //锁的销毁返回0成功传入锁的地址。 当然如果你想用一个全局的或者静态的锁。你可以用PTHREAD_MUTEX_INITIALIZER这个宏来为锁初始化。 用法pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;锁创建和初始化之后我们可以用pthread_mutex_lock 函数来加锁(本质是竞争锁因为多个线程只能有一个线程持有锁)。 pthread_mutex_unlock函数来解锁。 加锁到解锁中间的区域就是临界区。临界区只能同时被一个执行流访问 int pthread_mutex_lock(pthread_mutex_t *mutex); //竞争锁 int pthread_mutex_unlock(pthread_mutex_t *mutex); //解锁全局锁的使用 那么我们就用 PTHREAD_MUTEX_INITIALIZER 来初始化全局锁演示一下。 加锁后的代码 #includeiostream #includepthread.h #includeunistd.h#define THREAD_MAX_NUM 5int tickets 1000;pthread_mutex_t mtx PTHREAD_MUTEX_INITIALIZER; //创建全局锁void* ThreadRun(void* args) {int id *(int*)args;delete (int*)args;//抢票逻辑while(1){//抢票这段资源为临界资源我们为其加锁pthread_mutex_lock(mtx);if(tickets 0){usleep(1000);//延迟1000微秒tickets--; printf(thread %d 抢了一张票。还剩 %d 张票\n,id,tickets);pthread_mutex_unlock(mtx); //解锁 }else {//这里也必须解锁。如果上面条件不成立那么就要在这里进行解锁。pthread_mutex_unlock(mtx); //解锁 break; }}return nullptr; }int main() {pthread_t tids[THREAD_MAX_NUM];for(int i 0 ; i THREAD_MAX_NUM ; i){int* id new int(i1);pthread_create(tidsi , nullptr,ThreadRun,(void*)id);}for(int i 0 ; i THREAD_MAX_NUM ; i){pthread_join(tids[i],nullptr);}return 0; }我们为这个线程加上了互斥锁。那么我们来运行看看这段代码。 第一次测试 第二次测试 第三次测试 加锁之后我们可以明显的感觉到票数不会再被买到负数了这是能够保证线程安全的。但同样的速度也降低了很多。没加锁时的购票速度是很快的而加锁后的速度却变慢了很多。所以加锁也是有消耗的(主要在于临界区只能同时被单个执行流访问)。 局部锁的使用 局部互斥锁的函数上面已经介绍过了我们直接使用即可。但是要注意的是如果要把锁和id同时传给线程的话。我们最好指定一个ThreadData类。用来存储线程的数据。随后把这个类对象传给线程。 代码演示 #includeiostream #includepthread.h #includeunistd.h#define THREAD_MAX_NUM 5int tickets 10000;class ThreadData {public:ThreadData(int uid,pthread_mutex_t* mtx):_uid(uid),_mtx(mtx){}public:int _uid;pthread_mutex_t* _mtx; };void* ThreadRun(void* args) {ThreadData* data (ThreadData*)args;//抢票逻辑while(1){//抢票这段资源为临界资源我们为其加锁pthread_mutex_lock(data-_mtx);if(tickets 0){usleep(1000);//延迟1000微秒tickets--; printf(thread %d 抢了一张票。还剩 %d 张票\n,data-_uid,tickets);pthread_mutex_unlock(data-_mtx); //解锁 }else {//这里也必须解锁。如果上面条件不成立那么就要在这里进行解锁。pthread_mutex_unlock(data-_mtx); //解锁 break; }}return nullptr; }int main() {//创建局部锁 pthread_mutex_t mtx; //初始化局部锁 pthread_mutex_init(mtx,nullptr);pthread_t tids[THREAD_MAX_NUM];for(int i 0 ; i THREAD_MAX_NUM ; i){ThreadData* data new ThreadData(i1,mtx);pthread_create(tidsi , nullptr,ThreadRun,(void*)data);}for(int i 0 ; i THREAD_MAX_NUM ; i){pthread_join(tids[i],nullptr);}//销毁锁pthread_mutex_destroy(mtx);return 0; }代码的运行结果和上面的全局互斥锁是一样的。 互斥锁的原理 我们都知道锁可以保证临界资源的安全。但是锁也是被所有线程共享的。锁也是临界资源既然锁也是临界资源那么锁如何保证自己是安全的 就好比说一个1.5米的小瘦子说要保护一个2.0米的大胖子一样小瘦子凭什么说能保证大胖子的安全这时候小瘦子掏出了一把AK-47…大胖子才相信他能保护自己的安全… 这里有一份pthread_mutex_lock函数和pthread_mutex_unlock函数的伪代码 lock:movb $0, %alxchgb %al, mutex if(al寄存器的内容 0){return 0;}else 挂起等待;goto lock; unlock: movb $1, mutex 唤醒等待mutex的线程;return 0;xchgb是一条汇编指令意思是交换两个数的值。 而互斥锁的实现原理就是用一条汇编指令将%al寄存器的内容与mutex的内容进行交换。 接下来我将图文演示申请锁到释放锁的整个过程。 竞争锁的过程 首先看哪个线程先调用pthread_mutex_lock假设线程B先调用。 这时候已经在线程B中调用了pthread_mutex_lock函数。执行第一句代码 movb $0, %al 将0写入到寄存al中。 随后执行第二条指令xchgb %al, mutex 把al寄存器与mutex的内容进行交换。 突然这时候CPU要调度线程A了。那么CPU把当前线程B运行的数据保存到线程B的上下文。也就是al寄存器的内容也会被保存到线程B的上下文。随后调度线程A。 调度线程A之后在A调用了pthread_mutex_lock函数之后执行第一条汇编语句 movb $0, %al把0写入到al寄存器中。 随后调用第二条汇编语句 xchgb %al, mutex 把寄存器的值与mutex的值进行交换。 随后线程A继续往后执行if(al寄存器的内容 0) 不满足条件保存了自己的上下文之后被CPU挂起等待。 此时CPU又切换到了线程B。 CPU切换到线程B后线程B把保存的上下文交给了CPU所以此时al寄存器的内容被线程B替换为了1。 随后线程B继续往后执行if(al寄存器的内容 0) 条件为真最后pthread_mutex_lock返回0。返回后执行的就是临界区的代码也就是我们写的抢票逻辑。在这期间不管哪个线程被调度当xchgb %al, mutex这条指令被执行时。al的结果都不可能为1。因为mutex在第一次交换之后 ~ 锁释放之前会一直为0。所以第一个 执行xchgb %al, mutex 这条与mutex进行交换的汇编指令的线程将会获得临界区的访问权限也就是竞争锁成功而竞争锁成功后在释放锁之前这段时间临界区只有竞争锁成功的线程可以访问。所以这就保证了线程安全。 因为 xchgb %al, mutex 的操作是原子的。所以锁也是原子的因为只有这一句指令才是真正的竞争锁。即使在调用了 movb $0, %al这条汇编之后线程被切换。也无法影响什么因为锁只有一个只能让一个人换走。 释放锁的过程 释放锁的过程很简单先把mutex的值恢复即可。 然后再把所有挂起的线程唤醒 注意线程B在退出pthread_mutex_lock函数的时候对应保存的al寄存器的上下文就已经不存在了不要认为线程B在执行临界资源代码时上下文还保存着 al 1这个字段。这个字段在退出pthread_mutex_lock函数时就已经不存在了。是保存的上下文没了不是al寄存器没了切记切记不要弄混。
http://www.lebaoying.cn/news/73641.html

相关文章:

  • 做网站的一般都包维护吗国内外电子政务网站建设差距
  • 国外网站为什么不用备案一级a做爰片免费网站黄
  • 网站程序流程图wordpress的文章插件
  • 科技公司 网站设计经典案例wordpress带会员主题
  • 谷歌网站地图提交网站和网址的区别
  • 优质的网站建设案例快捷的网站建设软件
  • 东莞网网站公司简介西安高端品牌网站建设
  • 南京网站公司哪家好广州网站制作公司 番禺
  • 做奢侈品回收网站特点h5制作网站
  • 子网站 两微一端的建设方案怎么搞一个服务器建设网站
  • 企业网站运营方案怎么做相册网站
  • 学校加强网站建设石家庄网络公司推荐
  • django网站开发案例湖南智能网站建设推荐
  • 库存网站建设哪家好葫芦岛网站建设找思路
  • 炒股网站开发做货代的有哪些网站
  • 大型门户网站 要求怎么用php源代码做网站
  • 建站公司做的网站侵权了许昌哪个网站做苗木
  • 个人域名备案网站名称房地产如何做网站推广
  • 化妆品网站源码asp网站icp备案时间
  • 网站设置地图上海快速建站平台
  • 国外网站开发现状旺道seo推广效果怎么样
  • 网站长春网站建设网站水晶头怎么做
  • 无锡城乡建设部网站首页高端产业园开发
  • 网站开发项目组团队个人网站建设的背景
  • 做自行车网站应该注意什么合肥公司网站建设价格低
  • wordpress网站文章形式信息流投放平台
  • 心理网站免费建设东莞阳光网招聘官网
  • 伍佰亿网站建设怎么样自己建立一个网站
  • 长沙做最好网站wordpress 外贸主题
  • 视频解析网站如何做搜索建设网站多长时间