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

大蒜做营销型网站建设工程施工合同司法解释二

大蒜做营销型网站,建设工程施工合同司法解释二,详情页在线设计网站推荐,游戏开发者之家前言#xff1a; 在上一篇博客中#xff0c;我们讲解了什么是线程以及如何对线程进行控制#xff0c;那么了解了这些#xff0c;我们就可以在程序中创建多线程了#xff0c;可是多线程往往会带有许多问题#xff0c;比如竞态条件、死锁、数据竞争、内存泄漏等问题#…前言 在上一篇博客中我们讲解了什么是线程以及如何对线程进行控制那么了解了这些我们就可以在程序中创建多线程了可是多线程往往会带有许多问题比如竞态条件、死锁、数据竞争、内存泄漏等问题解决这些问题的关键在于如何实现线程的互斥和同步。 互斥 互斥是指一次只允许一个线程访问共享资源。这意味着当一个线程正在访问共享资源时其他线程必须等待直到该线程释放了资源。互斥通常通过互斥锁来实现。当一个线程获得了互斥锁时其他线程就无法获得该锁只能等待锁被释放。 同步 同步是指协调多个线程的执行顺序以确保它们按照预期的顺序执行。同步机制可以确保在多个线程之间正确的共享信息和控制流。常见的同步机制包括信号量、条件变量和屏障等。同步通常用于控制线程之间的竞态条件和避免数据竞争的发生。 今天我们从多线程中的数据竞争问题入手进一步了解多线程并且利用互斥机制来解决问题。 一多线程中的数据竞争 1.相关概念 在分析多线程中的数据竞争问题之前需要先了解一些相关的概念 并发访问 并发指的是在一段时间内多个任务交替地执行这些任务可能在同一时间段内启动和执行但并不一定同时执行。 临界资源临界区 临界资源是指在多线程环境下需要互斥访问的共享资源例如共享变量、共享内存区域、文件等。如果多个线程并发地访问和修改临界资源可能会导致数据竞争和程序错误。临界区是指包含对临界资源访问的代码段或程序区域这些代码段在任何给定时间点只能被一个线程执行以确保对临界资源的安全访问。 原子性 原子性是指在并发编程中操作的不可分割性即一个操作要么完全执行要么不执行不存在中间状态。原子操作在执行过程中不会被中断也不会被其他线程的操作干扰。 锁 在并发编程中锁Lock是一种同步机制用于控制对临界区的访问确保在任何给定时间点只有一个线程可以进入临界区执行代码。锁主要用于解决多线程环境下的竞态条件和数据竞争问题。 2.多线程抢票场景 在日常生活中高铁、火车抢票是很平常的一件事。假设票总量为1000用户进入系统如果剩余票的数量大于0那么就代表还有票用户抢到一张票剩余票数量减一。这个场景其实就是多线程并发访问的场景每个用户就代表一个线程票代表共享资源下面我们用代码来模拟一下 int ticket 10000; void *StartRoutine(void *args) {const string name static_castchar*(args);while(true){if(ticket 0){coutname get a ticket:ticketendl;ticket--;}else{break;}usleep(1000);}return nullptr; } int main() {pthread_t td1,td2,td3,td4;pthread_create(td1,nullptr,StartRoutine,(void*)thread-1);pthread_create(td2,nullptr,StartRoutine,(void*)thread-2);pthread_create(td3,nullptr,StartRoutine,(void*)thread-3);pthread_create(td4,nullptr,StartRoutine,(void*)thread-4);pthread_join(td1,nullptr);pthread_join(td2,nullptr);pthread_join(td3,nullptr);pthread_join(td4,nullptr);return 0; } 可是当我们运行程序时却发现运行的结果并不完全一致有时候票的编号甚至会减少到0或-1、-2这是为什么呢 显然我们这个程序的多线程并发访问共享数据是有问题的。 3.并发访问问题分析 在这个程序中对全局变量ticket进行访问的操作有: if(ticket 0) 和 ticket--; 如果想要对共享数据进行操作至少要分为三步 将内存中数据的值拷贝到CPU中的寄存器中。在CPU内部通过对寄存器的运算完成操作。将寄存器中的结果拷贝回内存中。 大致图解如下  如果是在单线程中上面这三步操作并不会被打断可是在多线程中由于上面的操作并不是原子的而且线程会被调度所以在中间可能会被打断。 比如线程A对ticket进行--操作在执行完第二步后寄存器中的内容已经由100减到99了然后线程A将要执行第三步时却发生了线程的调度例如线程A的时间片到了然后线程A会保存上下文数据并切走保存上下文就是将数据单独给自己一份。 这时线程B会开始它对ticket的操作并且线程B执行的很顺利在线程A调度完成返回时线程B已经完成了好几轮操作内存中的数据被修改只剩1了这时候线程A回来将继续执行第三步它会将自己上下文中的数据拷贝回内存这时候ticket又会编程99所以多线程中并发访问是不安全的。 二互斥锁 通过上面的问题分析我们要想安全的使用多线程必须对多个线程都需要访问的共享资源进行保护也就是将共享资源转变为临界资源。这样就可以实现线程的互斥通常情况下我们可以使用信号量、条件变量、原子操作、互斥锁、读写锁等今天我们利用互斥锁来实现线程互斥。 互斥锁Mutex是一种常见的同步机制用于保护临界资源确保在任何给定时间点只有一个线程能够访问临界资源。其基本原理是在进入临界区之前先锁定互斥锁然后在退出临界区时释放锁。 1.互斥锁的初始化 我们既可以在程序中定义全局的锁也可以定义局部的锁如果使用全局锁就需要 pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; 进行初始化 #include pthread.hint pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);参数 pthread_mutex_t *restrict mutex一个指向锁的指针。const pthread_mutexattr_t *restrict attr)是一个互斥锁属性对象的类型用于指定互斥锁的属性不需要设置时可以传入nullptr。 返回值  返回值为0表示函数执行成功互斥锁初始化成功。返回值为正数通常是正整数表示函数执行失败但没有明确的错误码定义具体含义可以根据系统的文档或头文件进行查找。返回值为负数表示函数执行失败并且会返回一个标准的错误码可以通过 errno 全局变量获取具体的错误码可以通过查看系统头文件 errno.h 来获得。 2.互斥锁的释放 释放一个锁可以通过pthread_mutex_destroy() 函数来实现 #include pthread.hint pthread_mutex_destroy(pthread_mutex_t *mutex); 返回值 返回值为0表示函数执行成功互斥锁销毁成功。返回值为正数通常是正整数表示函数执行失败但没有明确的错误码定义具体含义可以根据系统的文档或头文件进行查找。返回值为负数表示函数执行失败并且会返回一个标准的错误码可以通过 errno 全局变量获取具体的错误码可以通过查看系统头文件 errno.h 来获得。 3.互斥锁加锁 对临界资源加锁需要使用pthread_mutex_lock()函数它用于获取加锁互斥锁的函数。它的作用是在进入临界区之前尝试获取互斥锁如果互斥锁已经被其他线程持有则当前线程会被阻塞直到获取到互斥锁为止。 #include pthread.hint pthread_mutex_lock(pthread_mutex_t *mutex); 返回值 返回值为0表示函数执行成功当前线程成功获取了互斥锁。返回值为正数表示函数执行失败但没有明确的错误码定义具体含义可以根据系统的文档或头文件进行查找。返回值为负数表示函数执行失败并且会返回一个标准的错误码可以通过 errno 全局变量获取具体的错误码可以通过查看系统头文件 errno.h 来获得。 4.互斥锁解锁 对临界资源解锁需要使用pthread_mutex_unlock()函数它是用于释放解锁互斥锁的函数。它的作用是在临界区代码执行完毕后释放互斥锁以便其他线程可以获取到互斥锁进入临界区执行代码。 #include pthread.hint pthread_mutex_unlock(pthread_mutex_t *mutex); 返回值 返回值为0表示函数执行成功互斥锁成功释放。返回值为正数表示函数执行失败但没有明确的错误码定义具体含义可以根据系统的文档或头文件进行查找。返回值为负数表示函数执行失败并且会返回一个标准的错误码可以通过 errno 全局变量获取具体的错误码可以通过查看系统头文件 errno.h 来获得。 5.代码示例 pthread_mutex_t _mutex PTHREAD_MUTEX_INITIALIZER;int ticket 1000;void *StartRoutine(void *args) {const string name static_castchar *(args);while (true){pthread_mutex_lock(_mutex);if (ticket 0){cout name get a ticket: ticket endl;ticket--;sum;pthread_mutex_unlock(_mutex);}else{pthread_mutex_unlock(_mutex);break;}usleep(1000);}return nullptr; } int main() {pthread_mutex_init(_mutex, nullptr);pthread_t td1, td2, td3, td4;pthread_create(td1, nullptr, StartRoutine, (void *)thread-1);pthread_create(td2, nullptr, StartRoutine, (void *)thread-2);pthread_join(td1, nullptr);pthread_join(td2, nullptr);pthread_mutex_destroy(_mutex);return 0; } 上面的代码利用互斥锁实现了线程的互斥使得在多个线程抢票的时候不会出现数据竞争的问题也就不会让票的数量出现异常。 三锁的本质 大多数体系结构都提供了exchange或swap命令该指令的作用是将寄存器和内存单元的数据进行交换这个交换过程是原子的。 将pthread_mutex_lock()函数的汇编代码抽象出来 lock:movb $0, %alxchgb %al, mutexif(al寄存器里的内容 0){return 0;} else挂起等待;goto lock; xchgb作用将一个共享的mutex资源交换到自己的上下文中属于线程自己 。 这段伪代码的过程可以概括为  movb $0, %al将0赋值给al寄存器中。xchgb %al, mutex 将mutex的值赋值给al寄存器我们默认mutex是1大于0的值。判断al寄存器中的数据是否大于0如果大于0返回0代表获取锁成功如果小于0就挂起等待代表锁已经被别人获取了。 再看pthread_mutex_unlock()函数 unlcok:movb $l,mutex 唤醒等待Mutex的线程;return 0; 将线程上下文中mutex资源跟内存中的mutex交换。 我对加锁解锁的理解就是将锁看作一把钥匙。临界区看作一间房子钥匙原本挂在房子里第一个进入的线程会把钥匙放到自己口袋上下文里如果线程在临界区被调度走它会把钥匙也带走并关上房门这样别的线程想要进来但是没有钥匙而有钥匙的线程回来时还能够进入房子里当线程解锁就将钥匙放回到房子里并打开房门。 四死锁 1.概念 死锁是在并发系统中的一种常见问题它指的是两个或多个进程或线程因相互持有对方所需的资源而无法继续执行的状态。在死锁状态下各进程或线程都在等待其他进程或线程释放资源而导致它们都无法继续执行从而形成了一种僵局。 2.必要条件 互斥条件一个资源只能每次只能被一个执行流使用。 请求与保持条件一个执行流因为请求资源而阻塞时对已获得的资源保持不放。 不剥夺条件一个执行流已获得的资源在未使用之前不能强行剥夺。 循环等待条件若干执行流之间形成一种头尾相连的循环等待资源的关系。 3.解决方法 资源分配策略设计合理的资源分配策略避免同时持有多个资源从而减少死锁的发生可能性。加锁顺序确保所有进程或线程都以相同的顺序请求资源从而避免形成循环等待。超时机制对于资源请求设置超时机制如果超过一定时间仍未能获取资源则放弃当前请求避免长时间等待而导致死锁。死锁检测和解除定期检测系统中是否存在死锁并采取相应的措施来解除死锁例如终止部分进程或线程释放资源等。 五线程同步 1.同步概念 在上面的互斥示例程序中我们用抢票的例子来实现线程互斥可是在打印时却有一个现象总是有一个线程会抢占大多数的票导致了其他线程一直在等待抢不上票。这种现象叫做线程饥饿问题指的是一个或多个线程无法获得所需的资源或者无法被调度执行而长时间等待。 那么如何解决饥饿问题呢这就需要同步了。接下来我用一个比喻来理解线程同步。 假设有一个VIP自习室每次只能让一个同学进入学习只要自习室内有人别的同学就无法进入 张三在一天的早上6点第一个到达自习室并且一直在自习室里学习这就表示张三一直在使用里面的资源。到了中午12点张三想去吃饭但是吃饭出去的话就必须将钥匙归还然后吃完饭回来就得等待其他同学出来可张三并不想等所以张三又饿又不想出去他将钥匙放回去又拿回来在自习室里反复横跳。最后外面的同学一直没等到钥匙没吃上饭而张三一直持有钥匙也没吃上饭这就导致了其他同学的饥饿问题。 管理人员知道了这件事定了下面两条规矩 刚把钥匙归还的同学不能再次立即申请钥匙。在外面等待钥匙的同学必须排队。 定了这两条规矩张三再也不会反复横跳了也就不会导致饥饿问题了。这就是利用线程同步。 线程同步是指在多线程环境中对共享资源的访问进行协调和管理以确保线程之间的正确交互和数据一致性。在并发编程中线程同步是至关重要的因为多个线程同时访问共享资源可能导致数据竞争和不确定性的结果。 2.条件变量 条件变量是在多线程编程环境中用来线程通信的机制它通常和互斥锁使用来实现线程同步的效果。 条件变量实现了线程的等待和通知机制 等待Wait线程在等待条件变量时会释放它所持有的互斥锁并进入阻塞状态直到其他线程通知条件变量满足了某个条件。 通知Notify线程在某个条件发生变化时可以通过条件变量通知等待条件变量的一个或多个线程以唤醒它们继续执行。 2.1创建和销毁 #include pthread.hint pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); 2.2等待 #include pthread.hint pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); pthread_cond_wait 函数会使当前线程等待在指定的条件变量 cond 上同时会释放传入的互斥锁 mutex并将当前线程置于等待状态直到有其他线程调用 pthread_cond_signal 或 pthread_cond_broadcast 来唤醒它或者出现了异常情况如信号中断。 2.3唤醒 #include pthread.hint pthread_cond_signal(pthread_cond_t *cond); #include pthread.hint pthread_cond_broadcast(pthread_cond_t *cond); pthread_cond_signal pthread_cond_signal函数用于唤醒等待在条件变量上的一个线程。如果有多个线程等待在条件变量上调用pthread_cond_signal只会唤醒其中一个线程具体唤醒哪个线程由系统决定通常是按照先等待先唤醒的顺序。如果没有线程等待在条件变量上调用pthread_cond_signal也不会产生任何效果。 pthread_cond_broadcast pthread_cond_broadcast函数用于唤醒等待在条件变量上的所有线程。调用pthread_cond_broadcast会唤醒所有等待在条件变量上的线程使它们都可以继续执行。如果没有线程等待在条件变量上调用pthread_cond_broadcast也不会产生任何效果。
http://www.pierceye.com/news/126866/

相关文章:

  • 安顺建设局网站官网哪里有响应式网站企业
  • 唯品会一家做特卖的网站国家商标查询官方网站
  • 网站宝搭建网站环境做电商网站一般需要什么流程图
  • 南通网站建设团队wordpress广告产检
  • 做网站刷赞qq怎么赚钱邢台路桥建设总公司没有网站吗
  • 网站仿站教程常用外贸网站
  • 南昌市有帮做网站的吗纵横天下网站开发
  • pc网站直接转换成移动端的网站黑果云免费虚拟主机
  • 网站建设用什么科目wordpress当前分类链接地址
  • 做一万个网站网站做下载功能
  • 佛山建站模板制作wordpress加上live2d
  • 樟木头网站仿做深圳网站开发公司
  • 孙俪做的网站广告微信如何修改wordpress
  • 有什么手机做网站的免费ppt模板下载花
  • 网站建设团队技术介绍县级网站
  • 深圳营销型网站建设价格网站建设文化如何
  • 提交网站的入口地址网站建设灬金手指下拉十五
  • 连云港建设局网站学校网站建设管理相关规定
  • 什么网站做玩具的外贸网站监控系统
  • 从事网站美工建设厦门网站制作企业
  • 网站后台传图片南昌做网站要多少钱
  • 网站包括什么国内最大的域名交易平台
  • 做营销型网站 公司哈尔滨展览设计公司
  • 网站设计费用多少钱产品网页设计教程
  • 深圳公司网站建设设计网站推广的意义和方法
  • 网站需要哪些费用免费营销型网站模版
  • 如何做购物网站的教程wordpress酷炫插件
  • 建设信用卡网站登录网站建设和微信小程序
  • 邓州企业网站艺术设计方案
  • 广州市住房住建局网站永久免费的云电脑