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

中国建设企业银行网站首页wordpress修改个人头像

中国建设企业银行网站首页,wordpress修改个人头像,wordpress自动审核评论,智慧团建系统登录网站Linux学习笔记: https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言: 在上篇我们已经学习了关于线程的大部分知识,包括线程概念和线程控制等内容,今天我们来学习一下使用线程要做到的很…

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在上篇我们已经学习了关于线程的大部分知识,包括线程概念和线程控制等内容,今天我们来学习一下使用线程要做到的很重要的一步,那就是要保证线程的同步与互斥,从而确保线程安全问题,我们将通过一些生活中的例子和代码示例来理解如何做到线程的互斥与同步

目录

前提知识

线程的互斥

什么是线程的互斥

为什么需要线程的互斥

互斥的实现方法:互斥量

1. 互斥量的概念

2. 互斥量的接口函数

初始化与销毁

加锁与解锁

尝试加锁

3. 互斥量的使用

互斥锁实现互斥的原理

互斥量的使用场景

保护共享资源

避免竞态条件

互斥量的注意事项

死锁问题

性能开销

总结


前提知识

在深入探讨线程的互斥与同步之前,我们需要了解一些基本概念:

  • 并发与并行:并发是指多个任务在同一时间段内交替执行,而并行是指多个任务在同一时刻同时执行。

  • 临界区:临界区是指访问共享资源的代码段,这些资源在同一时刻只能被一个线程访问。

  • 竞态条件:当多个线程同时访问共享资源时,如果对资源的访问顺序不确定,可能会导致程序的行为不可预测,这种情况称为竞态条件。

线程的互斥

什么是线程的互斥

互斥是指在同一时刻,只允许一个线程访问共享资源。互斥机制确保了一个线程在访问共享资源时,其他线程不能同时访问该资源,从而避免了竞态条件的发生。

为什么需要线程的互斥

在多线程编程中,多个线程可能会同时访问共享资源。如果没有互斥机制,可能会导致以下问题:

  1. 数据不一致:当多个线程同时修改共享数据时,可能会导致数据的不一致。例如,两个线程同时对一个变量进行自增操作,可能会导致最终结果不正确。

  2. 竞态条件:竞态条件是指程序的输出依赖于线程的执行顺序,这会导致程序的行为不可预测。

下面我们通过一个春节购票系统来看一下会有什么问题:

我们定义一个全局变量count=1000表示有1000张票,我们再创建四个新线程,这四个新线程执行抢票工作,主线程等待回收它们,抢票的逻辑具体分为以下三步:

1、先检查是否还有余票。if(count>0)

2、如果有余票就让count--,同时子线程返回抢票的那一步

3、如果没有余票就退出

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;int count=1000;void *GetTickets(void *args)
{int thread_id = (int)(intptr_t)args; // 获取线程IDwhile(1){if(count>0){usleep(10000);   //模拟购票准备工作所需时间printf("[pthread %d] get a picket, the picket number: %d\n",thread_id,count);--count;}else{//如果没票,直接退出break;}}return nullptr;
}
int main()
{//创建四个新线程pthread_t tids[4];for(int i=0;i<4;i++){pthread_create(&tids[i],nullptr,GetTickets,(void*)(intptr_t)(i+1));}//阻塞等待回收线程for(int i=0;i<4;i++){pthread_join(tids[i],nullptr);}return 0;
}

执行结果(只截取了最后几行):

我们发现出现了错误,按照逻辑票应该是一张一张减少的,而且最终票数到0之后就不能再购买了,但是这里多购买了三张,那么原因是什么呢?

该错误是由以下两个原因组成的:

  • if 语句判断条件为真以后,代码可以并发的切换到其他线程。
  • usleep 是个模拟漫长业务的过程。在这个漫长的业务过程中,可能有其他线程会进入该代码段。

简单点来说就是在一个线程执行购票过程的时候,其它线程也可能会进入进行购票,因为线程是并发执行的,最终就可能会导致票数已经为0了,但是有些进程已经在票数为0前进入到if判断中了,就可能导致以上问题

根本原因就是--操作并不是原子的(简单来说并不是一次完成的),而是对应三条汇编指令:

  • load :将共享变量ticket从内存加载到寄存器中
  • update : 更新寄存器里面的值,执行-1操作
  • store :将新值,从寄存器写回共享变量ticket的内存地址
要解决以上问题,需要做到三点:
  • 代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
  • 如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临 界区。
  • 如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。

要做到以上三点,本质上就是需要一把锁,在一个线程进入临界区时将临界区的入口锁住不让其它线程进入,Linux提供的这个锁叫做互斥量

互斥的实现方法:互斥量

1. 互斥量的概念

互斥量是一种用于多线程编程的同步机制,用于确保同一时刻只有一个线程可以访问共享资源。互斥量的核心思想是通过加锁(Lock)和解锁(Unlock)操作来控制对共享资源的访问,从而避免多个线程同时修改共享资源导致的数据不一致或竞态条件。

互斥量通常用于保护临界区,即访问共享资源的代码段。当一个线程进入临界区时,它会先加锁;当线程离开临界区时,它会解锁,允许其他线程进入。

2. 互斥量的接口函数

1、互斥量的接口函数头文件都是 #include<pthread.h>

2、返回值都是:成功返回0,失败返回相应的错误码

初始化与销毁
pthread_mutex_init

用于初始化互斥量。

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
  • 参数

    • mutex:指向互斥量的指针。

    • attr:互斥量属性,通常设置为NULL以使用默认属性。

  • 返回值:成功返回0,失败返回错误码。

  1. PTHREAD_MUTEX_TIMED_NP:这时默认值,也就是普通锁。当一个线程加锁以后,其它申请该锁的线程组成一个资源等待队列,并在解锁后按优先级获得锁。这种解锁策略保证了资源分配的公平性。
  2. PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,允许同一个线程对同一个锁成功获得多次,并通过多次unlock解锁。如果是不同线程请求,则在加锁线程解锁后重新竞争。
  3. PTHREAD_MUTEX_ERRORCHECK_NP:检错锁,如果同一个线程请求同一个锁,则返回EDEADLK错误,否则与PTHREAD_MUTEX_TIMED_NP类型动作相同。这样就保证当不允许多次加锁时,不会出现最简单情况下的死锁。
  4. PTHREAD_MUTEX_ADAPTIVE_NP:适应锁,动作最简单的锁类型,仅等待解锁后重新竞争。
pthread_mutex_destroy

用于销毁互斥量,释放相关资源。

int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • 参数

    • mutex:指向互斥量的指针。

  • 返回值:成功返回0,失败返回错误码。

加锁与解锁
pthread_mutex_lock

用于加锁互斥量。如果互斥量已被其他线程锁定,当前线程会被阻塞,直到互斥量被解锁。

int pthread_mutex_lock(pthread_mutex_t *mutex);
  • 参数

    • mutex:指向互斥量的指针。

  • 返回值:成功返回0,失败返回错误码。

pthread_mutex_unlock

用于解锁互斥量,允许其他线程加锁。

int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 参数

    • mutex:指向互斥量的指针。

  • 返回值:成功返回0,失败返回错误码。

尝试加锁
pthread_mutex_trylock

尝试加锁互斥量。如果互斥量已被其他线程锁定,函数立即返回,不会阻塞当前线程。

int pthread_mutex_trylock(pthread_mutex_t *mutex);

参数

  • mutex:指向互斥量的指针。
  • 返回值:成功返回0,失败返回错误码(如EBUSY表示互斥量已被锁定)。

在锁的初始化上除了上面用函数来初始化外,我们也可以直接初始化:

这种初始化的方法叫做静态初始化,它将锁的声明、定义和初始化全部完成了,而且这样初始化的锁最后也不需要我们手动销毁

3. 互斥量的使用

我们使用一把互斥锁来对我们上面的购票系统进行一下加工:

首先我们先定义一个全局的互斥量,因为多个线程都要使用,定义全局的可以提高效率

主线程对所进行初始化,然后等待子线程都执行完后,回收子线程并且销毁锁

子线程在进入临界区时加锁,出临界区时解锁

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;int count=1000;
pthread_mutex_t mutex;void *GetTickets(void *args)
{int thread_id = (int)(intptr_t)args; // 获取线程IDwhile(1){//进入临界区时加锁pthread_mutex_lock(&mutex);if(count>0){usleep(10000);   //模拟购票准备工作所需时间printf("[pthread %d] get a picket, the picket number: %d\n",thread_id,count);--count;pthread_mutex_unlock(&mutex);    //买完票后退出重新进入购票队列,并把锁释放}else{//如果没票,直接退出pthread_mutex_unlock(&mutex);break;}}return nullptr;
}
int main()
{//创建新线程前先把锁初始化了pthread_mutex_init(&mutex,nullptr);//创建四个新线程pthread_t tids[4];for(int i=0;i<4;i++){pthread_create(&tids[i],nullptr,GetTickets,(void*)(intptr_t)(i+1));}//阻塞等待回收线程for(int i=0;i<4;i++){pthread_join(tids[i],nullptr);}//线程都回收后把锁也销毁了pthread_mutex_destroy(&mutex);return 0;
}

运行结果:

此时我们就发现我们最终的执行结果没有出现上面的问题了,这就是因为互斥锁保证了ticket--的原子性问题,每一次票数减一后才会有其它线程进入到临界区中

但是我们观察上面的执行结果,我们发现怎么所有的票都被线程2抢走了呢?这是因为最一开始是线程2先拿到锁抢到票,但是之后线程2对锁的竞争力就会远强于其它线程了,因为它将锁刚一释放就马上又获取了,所以我们采取的方法可以是:线程2抢完票之后可以让它短暂睡眠一会儿,这样其它线程就能够来争夺锁了

再次运行:

此时我们就可以发现所有线程都参与到抢票中来了,符合我们的预期结果

互斥锁实现互斥的原理

在了解锁的原理前,首先我们先来看一个小的知识点:

我们都知道寄存器是32位的,但是早期的寄存器实际上是只有16位的,现在的寄存器实际上可以看成两个16位的寄存器组合在一起,看成al和ah两块,al就是低位的那块,ah就是高位的那块

锁的原理图:

  • 第一步:首先将al寄存器清零
  • 第二步:将al寄存器中的内容和mutex的内容做一次交换,这个动作其实就是我们申请锁的动作
  • 第三步:判断,如果锁的数量大于0就会申请成功并退出,如果不大于0就会挂起等待

下面来看一下锁的伪代码对应的各个过程:

在整个加锁的过程中只有一个数值1存在,这个1要么保存在某个线程的私有的寄存器中,要么保存在共享的互斥锁变量mutex里。如果某个线程的寄存器中的值为1,说明该线程已经加锁成功。

锁本身其实也是作为共享资源存在的,那锁本身需要保护吗?

答案是不需要,因为锁在执行各种操作时其实已经是互斥的了

互斥量的使用场景

保护共享资源

互斥量最常见的用途是保护共享资源,例如全局变量、文件、数据库连接等。通过加锁和解锁操作,可以确保同一时刻只有一个线程访问共享资源。

避免竞态条件

互斥量可以避免竞态条件的发生。例如,在多个线程同时修改同一个变量时,使用互斥量可以确保每次修改操作是原子的。


互斥量的注意事项

死锁问题

死锁是指多个线程相互等待对方释放锁,导致程序无法继续执行。常见的死锁场景包括:

  • 线程A锁定互斥量X,然后尝试锁定互斥量Y;

  • 线程B锁定互斥量Y,然后尝试锁定互斥量X。

为了避免死锁,可以遵循以下原则:

  • 按固定顺序加锁;

  • 使用超时互斥量;

  • 避免嵌套加锁。

性能开销

互斥量的加锁和解锁操作会带来一定的性能开销,尤其是在高并发场景下。为了减少开销,可以:

  • 尽量减少临界区的范围;

  • 使用读写锁(std::shared_mutex)替代互斥量;

  • 使用无锁数据结构(Lock-Free Data Structures)。

总结

互斥量是多线程编程中不可或缺的同步机制,用于保护共享资源、避免竞态条件和数据不一致问题。通过加锁和解锁操作,互斥量确保同一时刻只有一个线程访问临界区。

在实际开发中,需要根据具体场景选择合适的互斥量类型,并注意避免死锁和性能开销问题。通过合理使用互斥量,可以编写出高效、可靠的多线程程序。

 除了互斥外,同步也是保证线程安全的很重要的概念,鉴于篇幅问题,同步我们放在下一篇进行讲解

本篇笔记:

感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!


文章转载自:

http://VWTdRx9y.xnqwk.cn
http://uc15G2OR.xnqwk.cn
http://cn4Gm1iA.xnqwk.cn
http://zZd4eaMd.xnqwk.cn
http://Hp0qtrX2.xnqwk.cn
http://fEbMfDLC.xnqwk.cn
http://ouJa6h8H.xnqwk.cn
http://00D7Q9UE.xnqwk.cn
http://2Qmgxud7.xnqwk.cn
http://Pxtt6AMo.xnqwk.cn
http://SHvZUoXG.xnqwk.cn
http://buB5Di61.xnqwk.cn
http://46m5w6Kk.xnqwk.cn
http://CArhocKu.xnqwk.cn
http://abC1xGKe.xnqwk.cn
http://GFpxmHvc.xnqwk.cn
http://UTasN9N6.xnqwk.cn
http://LgQd8fZT.xnqwk.cn
http://YuF2pAlG.xnqwk.cn
http://UpqDhiwy.xnqwk.cn
http://SMyMppZL.xnqwk.cn
http://EDkrl0Oz.xnqwk.cn
http://KZG7tTWp.xnqwk.cn
http://75i0r16b.xnqwk.cn
http://7DEH3MXv.xnqwk.cn
http://9ElBaV0S.xnqwk.cn
http://QMa2dJAu.xnqwk.cn
http://FxYlQMfm.xnqwk.cn
http://7E0gaB7z.xnqwk.cn
http://52pSiWHD.xnqwk.cn
http://www.dtcms.com/wzjs/774743.html

相关文章:

  • 张家界网站建设企业wordpress 在线留言
  • 网站分类 维护济南最新消息今天
  • 新增网站惠州市建设局网站
  • 深圳做网站排名公司哪家好北京网站建设销售招聘
  • 网站建设技术规范网站前置审批在哪里办
  • 淄博网站建设给力臻动传媒移动网站开发技术
  • 创造你魔法官方网站起做欢的事温州手机网站开发
  • 微信官方网站是什么地图网站怎么做的
  • 网站建设费是业务宣传费吗wordpress模仿知乎
  • 青岛市建设局网站停工seo公司网站推广
  • 3d网站开发成本企业关键词排名优化网址
  • 研发项目备案在哪个网站做简单php企业网站源码
  • 广州网页设计师工资一般多少上海搜索引擎优化seo
  • 铭讯网站建设上海网站设计的公司
  • 网站分站系陕西省建设造价协会网站
  • 求购做网站app平台开发需要的资源与团队
  • ps扩展插件网站外贸推广公司哪家好
  • 宝塔怎么做两个网站的解析宁波网络营销推广
  • 宁波网站推广公司报价工厂订单外发代加工外发加工网
  • 建一个网站大约需要花费多少钱做美容一般在哪个网站团购比较好
  • 视频号的网站链接做美食网站的模板
  • 网站申请微信支付小制作大全简单又漂亮
  • 可以自己做网站这么做中国中小企业官网
  • 做app推广上哪些网站吗扬州外贸网站建设公司
  • 棋牌网站制作价格淘客网站自己做
  • 浙江高端网站建设专门做顶账房的网站
  • 公司网站建设费用账务处理cpa个人网站怎么做
  • 易企秀怎么做招聘网站超链接系统优化设置
  • 怎么做个手机版的网站吗网站建设项目开发
  • wordpress不显示模板大连网络推广网站优化找哪家好