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

学校网站建设企业sem优化软件选哪家

学校网站建设企业,sem优化软件选哪家,网络维护合同,微信小程序制作详细流程上篇文章我们对线程 | 线程介绍线程控制介绍后#xff0c;本篇文章将会对多线程中的线程互斥与互斥锁的概念进行详解。同时结合实际例子解释了可重入与不被重入函数、临界资源与临界区和原子性的概念。希望本篇文章会对你有所帮助。 文章目录 引入 一、重入与临界 1、1 可… 上篇文章我们对线程 | 线程介绍线程控制介绍后本篇文章将会对多线程中的线程互斥与互斥锁的概念进行详解。同时结合实际例子解释了可重入与不被重入函数、临界资源与临界区和原子性的概念。希望本篇文章会对你有所帮助。 文章目录 引入 一、重入与临界 1、1 可重入与不被重入函数 1、1、1 不可重入函数 1、1、2 可重入函数 1、2 临界资源与临界区 1、2、1 临界资源 1、2、2 临界区 1、3 原子性 二、 线程互斥 2、1 分析原因与再次理解概念 2、2 互斥锁 2、2、1 什么是互斥锁 2、2、2 pthread_mutex_t  2、2、3 pthread_mutex_init 初始化 2、3 抢票加互斥锁 2、4 互斥锁总结 三、互斥锁实现原理 ‍♂️ 作者Ggggggtm ‍♂️  专栏Linux从入门到精通   标题线程互斥  ❣️ 寄语与其忙着诉苦不如低头赶路奋路前行终将遇到一番好风景 ❣️ 引入 我们先看一段多线程抢票的代码 int tickets10000;void* getTickets(void* args) {while(true){if(tickets0){usleep(1000);printf(%s: %d\n,(char*)args,tickets);tickets--;}elsebreak;}return nullptr; } int main( void ) {srand(time(nullptr));pthread_t t1, t2, t3, t4;pthread_create(t1, NULL, getTickets, (void*)thread 1);pthread_create(t2, NULL, getTickets, (void*)thread 2);pthread_create(t3, NULL, getTickets, (void*)thread 3);pthread_create(t4, NULL, getTickets, (void*)thread 4);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);return 0; }   上述代码就是创建了四个新线程同时去抢票当票数为0时就停止抢票。那我们看一下运行结果   怎么票数会被抢到负数呢上述代码明明就是在票数为0的时候就终止了。这是为什么呢我们接着往下看。 一、重入与临界 1、1 可重入与不被重入函数 我们先看下图   上图就是一个链表的节点插入。我们之前学的是单进程进行链表的插入也就是但是执行流进行的插入。当然但执行流是没有任何问题。如果现在有多个执行流在执行链表的插入呢会不会出现意想不到的问题呢我们看如下情况。   main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换 到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的 两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续 往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后 向链表中插入两个节点,而最后只有一个节点真正插入链表中了。我们发现就出现了一个节点的丢失。 1、1、1 不可重入函数 不可重入函数Non-reentrant Function它在被多个任务并发调用时可能会出现竞争条件Race Condition或数据不一致的问题。  在上述情况中我们发现插入节点的函数被多个执行流执行时发生了意想不到的错误出现了数据丢失的问题。我们称之为该函数不可被重入。 1、1、2 可重入函数 可重入函数Reentrant Function是指可以被同时多个任务调用而不会发生错误或产生意外结果的函数。换句话说可重入函数在被多个任务并发调用时能够保持其内部状态的一致性。我们所学的大部分函数都是不可被重入的。 1、2 临界资源与临界区 1、2、1 临界资源 临界资源Critical Resource是指在并发编程中多个任务或线程之间共享的某一资源但同时只能被一个任务或线程访问和操作的资源。 1、2、2 临界区 临界区Critical Section是指代码中访问临界资源的那一部分代码段或区域。在临界区内部任务或线程可以对临界资源进行读取、写入或其他操作。因为临界资源只能被一个任务或线程访问所以必须确保在任何时刻只有一个任务或线程能够进入临界区以避免对临界资源造成竞争条件和不确定的结果。  这里先给大家把概念引出后面会再次结合例子来解释临界资源与临界区。  1、3 原子性 其实我们也不难发现上述情况问题的所在。一是有多个执行流在执行同一个操作。因为当一个进程在运行时任何时刻都有可能被切换下去去执行另一个进程。二是插入操作分为多个步骤完成。两点一结合就是在插入没有完成的时候该执行流就被切换走了进而导致出现问题。原子性是一个操作没有中间的状态。就是一个操作要执行就执行结束要不就不执行没有其他的状态。加入插入操作是原子性的也就不会发生数据错误。 二、 线程互斥 2、1 分析原因与再次理解概念 上面我们了解了重入与临界的概念后我们再看引入中抢票的例子。抢票例子是多线程进行抢票。也就是有多个执行流在进行抢票。我们以为tickets--在CPU內部直接减1就完了吗实际上并不是。具体如下图   假设线程1抢票时此时票好有10000张。   于是就进行判断打印。刚打印完把tickets10000读到寄存器中还没有抢票tickets--该线程的时间片到了被切换下去。此时线程1的上下文会被保存起来。然后线程2被调度。   由于各种原因线程2的优先级较高。线程二就行行疯狂抢票。一下子抢了1000多张票。然后线程2被切换下去线程1重新被调度。操作系统会先回复线程1的上下文数据。此时CPU拿到的tickets又变成了10000线程1再进行抢票。此时就出现了CPU与内存中的数据错乱的问题。 我们再看tickets--。这也正是tickets能够变成负数的原因。当一个tickets1时发现能够抢票。当时刚执行完打印也就是并没有抢票就被切换下去了此时该线程也并没有保存tickets数据。同时其它线程被切换上来进行抢票后票数变为0。再次恢复之前被切换下去的下线程此时已经没票了但是该线程以为还有票于是当把tickets数据读到寄存器中后tickets为0进行计算--操作再次写入内存票数就变成了负数。 上述讲解了两种出现错误的情况。针对上述例子我们再来看一下临界资源和临界区   tickets-- 操作并不是原子操作而是对应三条汇编指令 load 将共享变量ticket从内存加载到寄存器中update : 更新寄存器里面的值执行-1操作store 将新值从寄存器写回共享变量ticket的内存地址 要解决以上问题需要做到三点 代码必须要有互斥行为当代码进入临界区执行时不允许其他线程进入该临界区。如果多个线程同时要求执行临界区的代码并且临界区没有线程在执行那么只能允许一个线程进入该临界区。如果线程不在临界区中执行那么该线程不能阻止其他线程进入临界区。   要做到这三点本质上就是需要一把锁。Linux上提供的这把锁叫互斥量 2、2 互斥锁 什么是锁在Linux操作系统中锁Lock是一种同步机制用于保护共享资源免受多个并发线程访问和修改的干扰。锁可以防止多个线程同时访问或修改共享资源从而确保对共享资源的安全访问。 2、2、1 什么是互斥锁 当有一个线程申请互斥锁资源也就是加锁成功后其他线程就不会申请所资源成功。其他线程也就会进入阻塞等待状态。可以理解为把其他线程阻塞在外面了不能有多个线程同时执行去申请互斥锁。这就是线程互斥。同一个线程不能执行互斥锁内的资源同时只有一个线程能够执行。当进行对所资源释放也就是解锁后其他线程才可申请所资源。 2、2、2 pthread_mutex_t  pthread_mutex_t是一个用于实现线程同步的互斥量类型也就是我们所说的互斥锁的类型。pthread_mutex_t可以用来保护共享资源防止多个线程同时访问和修改数据而导致的竞争条件。使用pthread_mutex_t时通常需要进行以下步骤初始化、加锁、解锁、销毁。 下面对每个步骤进行详细解释并提供一个示例代码 初始化互斥锁 可以使用pthread_mutex_init函数来初始化互斥锁。初始化后的互斥锁状态为未锁定状态。 示例代码 pthread_mutex_t mutex; // 定义互斥锁变量// 初始化互斥锁 int result pthread_mutex_init(mutex, NULL); if (result ! 0) {// 初始化失败的处理逻辑 } 加锁 使用pthread_mutex_lock函数可以将互斥锁设置为锁定状态如果互斥锁已被其他线程锁定当前线程会进入阻塞状态直到获取到锁。 示例代码 // 加锁 int result pthread_mutex_lock(mutex); if (result ! 0) {// 加锁失败的处理逻辑 } 解锁 使用pthread_mutex_unlock函数可以将互斥锁设置为未锁定状态释放锁供其他线程使用。 示例代码 // 解锁 int result pthread_mutex_unlock(mutex); if (result ! 0) {// 解锁失败的处理逻辑 } 销毁互斥锁 在不再需要使用互斥锁时可以使用pthread_mutex_destroy函数来销毁已初始化的互斥锁。 示例代码 // 销毁互斥锁 int result pthread_mutex_destroy(mutex); if (result ! 0) {// 销毁失败的处理逻辑 } 注意事项 pthread_mutex_t的初始化应该在使用前完成并且应该确保互斥锁变量的作用域覆盖了所有对该锁的访问。对于每个加锁操作都应该有对应的解锁操作以避免资源泄漏和死锁的情况发生。建议在使用互斥锁时考虑锁的粒度尽量保持锁的范围小并且锁的持有时间短以提高并发性能。   后面也会对注意事项接进行解释。线面我们先来看一下对pthread_mutex_t 进行初始化处理操作的详解。其他操作简单就不再解释。 2、2、3 pthread_mutex_init 初始化 pthread_mutex_init函数是一个用于初始化互斥锁的函数它的原型如下 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);   该函数主要用于将传入的mutex指向的互斥锁对象进行初始化使其可以正确地使用。   参数说明 mutex指向要初始化的互斥锁对象的指针。attr指向包含互斥锁属性的对象的指针。可以通过该参数来设置互斥锁的属性如果为NULL则使用默认属性。   返回值 若成功返回0若失败返回错误代码。   调用pthread_mutex_init函数会对互斥锁进行初始化包括分配内存和设定默认属性。属性我们一般选择传入nullptr就是默认属性。 当pthread_mutex_t 对象为全局时我们也可选择不用 pthread_mutex_init 进行初始化。可直接使用宏PTHREAD_MUTEX_INITIALIZER来初始化。代码如下 pthread_mutex_t mtxPTHREAD_MUTEX_INITIALIZER; 2、3 抢票加互斥锁 我们对抢票的临界区加锁这样就不会出现多个执行流去访问临界资源的情况了。   代码如下 int tickets10000; pthread_mutex_t mtxPTHREAD_MUTEX_INITIALIZER;void* getTickets(void* args) {while(true){pthread_mutex_lock(mtx);if(tickets0){usleep(1000);printf(%s: %d\n,(char*)args,tickets);tickets--;pthread_mutex_unlock(mtx);}else{pthread_mutex_unlock(mtx);break;}usleep(rand()%2000);}return nullptr; } int main( void ) {srand(time(nullptr));pthread_t t1, t2, t3, t4;pthread_create(t1, NULL, getTickets, (void*)thread 1);pthread_create(t2, NULL, getTickets, (void*)thread 2);pthread_create(t3, NULL, getTickets, (void*)thread 3);pthread_create(t4, NULL, getTickets, (void*)thread 4);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);return 0; }   我们再看运行结果 上述代码是定义全局变量的互斥锁。我们再来看一下局部变量的互斥锁是怎么使用的。代码如下 #define THREAD_NUM 5int tickets10000;class ThreadData { public:ThreadData(const string n,pthread_mutex_t* pm):tname(n),pmtx(pm){}public:string tname;pthread_mutex_t* pmtx; };void* getTickets(void* args) {ThreadData* data(ThreadData*) args;while(true){pthread_mutex_lock(data-pmtx);if(tickets0){usleep(1000);printf(%s: %d\n,data-tname.c_str(),tickets);tickets--;pthread_mutex_unlock(data-pmtx);}else{pthread_mutex_unlock(data-pmtx);break;}usleep(rand()%2000);}return nullptr; } int main( void ) {srand(time(nullptr));pthread_t t1, t2, t3, t4;pthread_mutex_t mtx;pthread_mutex_init(mtx,nullptr);pthread_t t[THREAD_NUM];// 多线程抢票的逻辑for(int i 0; i THREAD_NUM; i){std::string name thread ;name std::to_string(i1);ThreadData *td new ThreadData(name, mtx);pthread_create(t i, nullptr, getTickets, (void*)td);}for(int i 0; i THREAD_NUM; i){pthread_join(t[i], nullptr);}pthread_mutex_destroy(mtx);return 0; } 2、4 互斥锁总结 加锁就是串行执行了吗?答案是是的。任何时候只允许申请锁成功的线程执行临界区代码。因为变为串行执行所以我们要在加锁的时候一定要保证加锁的粒度越小越好不必要的代码可放在锁外。   加锁了之后线程在临界区中是否会切换会有问题吗答案是会被切换的。但是并不会出现问题。虽然被切换了但是你是持有锁被切换的所以其他抢票线程要执行临界区代码也必须先申请锁锁它是无法申请成功的所以也不会让其他线程进入临界区就保证了临界区中数据一致性只要一个线程且需要访问临界资源就必须申请锁。   在没有持有锁的线程看来对我最有意义的情况只有两种:1.线程1没有持有锁(什么都没做)2线程1释放锁(做完)此时我可以申请锁   要访问临界资源每一个线程都必须现申请锁每一个线程都必须先看到同一把锁且访问它锁本身不就是一种共享资源吗那么谁来保证锁的安全呢?所以为了保证锁的安全申请和释放锁必须是原子性的。所以是由它自己自己保证。那么是怎么保证的呢 三、互斥锁实现原理 经过上面的例子大家已经意识到单纯的 i 或者 i 都不是原子的有可能会有数据一致性问题。   为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的 总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期。    具体可结合下图理解   其实我们也不难发现申请互斥锁资源的在底层本质就是一个交换指令。而交换的本质就是使其在内存中的共享资源变成了线程的私有资源当交换后值为1时就说明申请互斥锁资源成功。从头到尾一直是在交换一直是只有一个1。所以保证了只有一个线程能够申请互斥锁资源成功。
http://www.yutouwan.com/news/189530/

相关文章:

  • 杭州seo网站推广排名国家认可提升学历正规机构
  • 做服装网站设计书原创代写文章平台
  • 怎么做快递网站的分点做外贸怎样免费登录外国网站
  • 网站底部设计代码建立个网站需要多少钱
  • 自己做项目的网站app免费版下载安装
  • 最新的网站建设软件网站设计用处
  • 画网站 模板网站灰色 代码
  • 电商平台建设做网站wordpress留言源码
  • 雅安网站制作网页制作模板和库的联系与区别
  • 制冷设备东莞网站建设wordpress改写rewrite
  • 官网网站建设需求文档做学校网站需要备案么
  • 软文网站开发中国国家培训网官网
  • 网站开发研发合同国外做婚纱摄影店设计的网站
  • 怎样查到一些做品牌包的网站网站建设流程报告
  • 企业网站设计说明wordpress 清空换行
  • 医院网站建设方案详细注册资金多少有什么利弊
  • 网站建设及宣传管理规定国企500强完整名单
  • 开网店卖什么产品比较好企业网站建设中图片优化的方法
  • 如果自己做网站家私家具网上商城
  • 专门做汽配的网站移动微网站
  • 网站地图xml文件学计算机的毕业后可以找什么工作
  • 国外试用网站空间天津百度
  • 互联网个人用户网站深圳平面设计公司排名前十强
  • 新网站制作怎么样沙田东莞网站建设
  • 做企业平台的网站有哪些方面简单的视频制作软件推荐
  • 阿里云做网站送服务器医疗方面的网站建设
  • 高性能网站建设指南 百度云wordpress 导航 分类
  • 网站建站套餐以下什么是网络营销的特点
  • 简述seo对各类网站的作用公司的网站制作
  • 医疗不可以做网站网站建设方案及报