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

门户网站开发技术建设充值网站多钱

门户网站开发技术,建设充值网站多钱,wordpress网站的搭建,网络营销和网络推广✨✨ 欢迎大家来到贝蒂大讲堂✨✨ #x1f388;#x1f388;养成好习惯#xff0c;先赞后看哦~#x1f388;#x1f388; 所属专栏#xff1a;Linux学习 贝蒂的主页#xff1a;Betty’s blog 与Windows环境不同#xff0c;我们在linux环境下需要通过指令进行各操作养成好习惯先赞后看哦~ 所属专栏Linux学习 贝蒂的主页Betty’s blog 与Windows环境不同我们在linux环境下需要通过指令进行各操作以下是常见操作的指令 1. 线程互斥 1.1 基本概念 临界资源 多线程执行流共享的资源叫做临界资源。临界区 每个线程内部访问临界资源的代码就叫做临界区。互斥 任何时刻互斥保证有且只有一个执行流进入临界区访问临界资源通常对临界资源起保护作用。原子性 不会被任何调度机制打断的操作该操作只有两态要么完成要么未完成。 进程之间进行通信需要先创建第三方资源使得不同的进程能够看到同一份资源。由于这份第三方资源可以由操作系统中的不同模块提供所以进程间通信的方式有很多种。在进程间通信中这个第三方资源被称为临界资源而访问第三方资源的代码则被称为临界区。 与之不同的是多线程的大部分资源都是共享的。因此线程之间进行通信并不需要像进程那样费力地去创建第三方资源。 例如我们在代码中只需要在全局区定义一个count变量新线程可以每隔一秒对该变量进行加一操作主线程也可以每隔一秒获取count变量的值并进行打印。 #include iostream #include unistd.h #include pthread.h #include stdio.h #include stdlib.h #include sys/types.h using namespace std; int count 0; void *Routine(void *args) {while (true){count;sleep(1);}pthread_exit((void *)0); } int main() {pthread_t tid;pthread_create(tid, nullptr, Routine, nullptr);while (true){cout The value of count is count endl;sleep(1);}pthread_join(tid, nullptr);return 0; }在当前情境下我们相当于实现了主线程和新线程之间的通信。其中全局变量count起着关键作用它被称为为临界资源原因在于它被多个执行流所共享。而主线程中的 cout 操作以及新线程中的 count 操作被称作临界区。这是因为这些代码片段对临界资源进行了访问。 但是我们同样观察到打印数据并没有 1这就是多执行流对临界资源操作常引发的数据不一致问题。 同样我们也可以下面抢票程序的实现具体演示如果不对临界资源进行限制可能会出现的危害。 #include iostream #include unistd.h #include pthread.h #include cstdio #include cstdlib using namespace std; int tickets 1000; void *getTickets(void *args) {string name thread ;name to_string((uint64_t)args);while (true){if (tickets 0){usleep(1000);cout [ name ] get a ticket,left: --tickets endl;}else{break;}}cout name is quit! endl;pthread_exit((void *)0); } int main() {pthread_t tids[5];for (uint64_t i 0; i 5; i){pthread_create(tids i, nullptr, getTickets, (void *)i);}for (int i 0; i 5; i){pthread_join(tids[i], nullptr);}return 0; }剩余票数出现负数这明显不符合我们的常识与预期之所以出现这种情况本质就是 tickets就是我们的临界资源--tickets也 并不是原子的在多执行流同时执行时就可能会发生这种问题。 为什么 --tickets并不是原子的呢 因为从汇编角度看我们的 --操作其实是不安全的他们转成汇编一般会对应三条汇编指令从内存中读取数据到 CPU 中CPU 内进行操作CPU 将结果写回内存。进程在运行的时候随时可能被切换。 1.2 互斥量 为了解决这个问题我们就引入了互斥保证一次只有一个执行流访问临界资源而为了实现互斥我们就需要保证临界区的原子性即临界区的资源要么被执行完成要么不执行只存在这两态。 要做到这些本质就是需要一把锁所以 Linux就引入一个锁并将其称为互斥量。 1.3 互斥量的接口 1.3.1 初始化互斥量 我们可以使用pthread_mutex_init初始化互斥量使用方法如下 函数原型int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);参数 mutex需要初始化的互斥量。attr初始化互斥量的属性一般设置为 nullptr 即可。 返回值互斥量初始化成功返回0失败返回错误码。 这种调用函数接口初始化互斥量的方式我们称为动态分配除此之外我们也能使用如下的方式进行初始化我们将其称为静态分配。 pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; 1.3.2 销毁互斥量 我们可以使用pthread_mutex_destory销毁互斥量使用方法如下 函数原型int pthread_mutex_destroy(pthread_mutex_t *mutex);参数mutex需要销毁的互斥量。返回值成功返回 0失败返回错误码。 其中销毁互斥量需要注意以下几点 使用PTHREAD_MUTEX_INITIALIZER静态初始化的互斥量不需要销毁。不能销毁一个已经加锁的互斥量。已经销毁的互斥量要确保后面不会有线程再尝试加锁。 1.3.3 加锁互斥量 加锁本质就是让被加锁区域的代码具有原子性只能同时被一个线程访问。我们可以使用pthread_mutex_lock对互斥量进行加锁使用方法如下 函数原型int pthread_mutex_lock(pthread_mutex_t *mutex);参数mutex需要加锁的互斥量。返回值成功返回 0失败返回错误码。 如果一个线程在执行过程中遇见该接口并且该锁已被其他线程申请那么该线程此时就会陷入阻塞状态等待其解锁。 1.3.4 解锁互斥量 在加完锁之后我们不可能让所有代码只被一个执行流访问所以我们需要合适的地方解锁我们可以使用pthread_mutex_unlock对互斥量进行解锁使用方法如下 函数原型int pthread_mutex_unlock(pthread_mutex_t *mutex);参数mutex需要解锁的互斥量。返回值成功返回 0失败返回错误码。 知道了这些概念之后我们就可以对前面的抢票逻辑进行修改 #include iostream #include unistd.h #include pthread.h #include cstdio #include cstdlib using namespace std; int tickets 1000; pthread_mutex_t mutex; void *getTickets(void *args) {string name thread ;name to_string((uint64_t)args);while (true){pthread_mutex_lock(mutex);if (tickets 0){usleep(1000);cout [ name ] get a ticket,left: --tickets endl;pthread_mutex_unlock(mutex);}else{pthread_mutex_unlock(mutex);break;}}cout name is quit! endl;pthread_exit((void *)0); } int main() {pthread_mutex_init(mutex, nullptr);pthread_t tids[5];for (uint64_t i 0; i 5; i){pthread_create(tids i, nullptr, getTickets, (void *)i);}for (int i 0; i 5; i){pthread_join(tids[i], nullptr);}pthread_mutex_destroy(mutex);return 0; }其实在大部分情况下加锁本身都是有损于性能的事因为它使多执行流由并行执行变为了串行执行这几乎是不可避免的。所以我们需要在合适的位置加锁与解锁尽可能减少锁引入锁带来的性能开销成本。 1.4 互斥量的原理 当我们使用互斥量之后临界区的代码对于其他线程来说只有两种状态加锁与解锁这就保证了临界区的原子性。而我们要知道锁本身就是能被所有执行流访问的资源所以锁本身也是一种临界资源当然也需要保证其原子性所以锁本身实现就是原子的。 为了实现互斥锁操作大多数体系结构都提供了 swap 或 exchange 指令该指令的作用就是把寄存器和内存单元的数据相交换以下就是实现加锁 lock与解锁 unlock的伪代码 我们首先可以认为 mutex 的初始值为1al 是计算机中的一个寄存器当线程申请锁时需要执行以下步骤 先将 al 寄存器中的值清0。该动作可以被多个线程同时执行因为每个线程都有自己的一组寄存器上下文信息执行该动作本质上是将自己的 al 寄存器清0。然后交换 al 寄存器和 mutex 中的值。xchgb 是体系结构提供的交换指令该指令可以完成寄存器和内存单元之间数据的交换。 最后判断 al 寄存器中的值是否大于0。若大于0则申请锁成功此时就可以进入临界区访问对应的临界资源否则申请锁失败需要被挂起等待直到锁被释放后再次竞争申请锁。 我们需要注意的是CPU内的寄存器不是被所有的线程共享的每个线程都有独自的一组寄存器所以改变当前线程 al寄存器的值并不会影响其他线程的 al寄存器 当然内存中的数据因为属于同一个进程所以各个线程是共享的。 而当线程释放锁时需要执行以下步骤 将内存中的 mutex 置回1使得下一个申请锁的线程在执行交换指令后能够得到1。唤醒等待 mutex 的线程让它们继续竞争申请锁。 在线程释放锁的过程中并没有将当前线程的 al 寄存器中的值清0这不会造成任何影响因为每次线程在申请锁时都会先将自己 al 寄存器中的值清0再执行交换指令。 所以我们申请锁的本质就是执行 xchgb这一条汇编指令因为只有一条所以只有已执行与未执行两种状态具有原子性。 2. 线程安全 线程安全是指在多线程环境下多个线程并发执行同一段代码时不会出现不可预期的错误结果或数据不一致的情况。 常见线程不安全的情况有 不保护共享变量的函数。函数状态随着被调用状态发生变化的函数。返回指向静态变量指针的函数。调用线程不安全函数的函数。 而线程安全的情况有 每个线程对全局变量或者静态变量只有读取的权限而没有写入的权限一般来说这些线程是安全的。类或者接口对于线程来说都是原子操作。多个线程之间的切换不会导致该接口的执行结果存在二义性。 而可重入函数与线程安全的联系有 函数是可重入的那就是线程安全的。函数是不可重入的那就不能由多个线程使用有可能引发线程安全问题。如果一个函数中有全局变量那么这个函数既不是线程安全也不是可重入的。 而可重入函数与线程安全的区别有 可重入函数是线程安全函数的一种。线程安全不一定是可重入的而可重入函数则一定是线程安全的。如果对临界资源的访问加上锁则这个函数是线程安全的但如果这个重入函数的锁还未释放则会产生死锁因此是不可重入的。 3. 死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源但因互相申请被其他进程所占用不会释放的资源而处于的一种永久等待状态。 比如说如果某一执行流连续申请了两次锁就会陷入死锁状态。具体情况如下当该执行流第一次申请锁时通常会申请成功。然而第二次申请锁时由于此锁已经被该执行流自身持有再次申请会失败进而导致该执行流被挂起。而此时这个锁在其自己手上可它又处于被挂起的状态根本没有机会去释放锁。这样一来该执行流将永远无法被唤醒从而处于死锁状态。 #include iostream #include unistd.h #include pthread.h #include cstdio #include cstdlib using namespace std; pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER; void*Routine(void*args) {pthread_mutex_lock(mutex);pthread_mutex_lock(mutex);return nullptr; } int main() {pthread_t tid;pthread_create(tid,nullptr,Routine,nullptr);pthread_join(tid,nullptr);return 0; }其中形成死锁的必要条件有以下四个 互斥条件 一个资源每次只能被一个执行流使用。请求与保持条件 一个执行流因请求资源而阻塞时对已获得的资源保持不放。不剥夺条件 一个执行流已获得的资源在未使用完之前不能强行剥夺。循环等待条件 若干执行流之间形成一种头尾相接的循环等待资源的关系。 而为了避免死锁我们一般也可以从这几个角度思考 破坏死锁的四个必要条件。加锁顺序一致。避免锁未释放的场景。资源一次性分配。 除此之外还有一些避免死锁的算法常见的比如有死锁检测算法和银行家算法。 4. 线程同步 4.1 饥饿问题 线程饥饿指的是某些线程由于各种原因一直无法获得足够的 CPU 时间来执行任务从而处于长期等待或执行时间极少的状态。 产生线程饥饿的原因主要有以下几种 高优先级线程抢占如果系统中有高优先级的线程持续占用 CPU 资源那么低优先级的线程就可能长时间得不到执行机会从而导致饥饿。例如在实时系统中高优先级的实时任务可能会一直抢占低优先级的普通任务。 线程调度不公平如果线程调度算法不合理或者存在缺陷可能导致某些线程被不公平地对待长期无法获得执行机会。比如某些调度算法可能偏向于某些特定类型的线程或者特定状态的线程。 资源竞争当多个线程竞争有限的资源时一些线程可能因为一直无法获得所需资源而被阻塞从而无法执行。例如多个线程竞争一个互斥锁而某些线程总是在竞争中失败就可能陷入饥饿状态。 线程饥饿会导致系统性能下降部分任务无法及时完成甚至可能使整个系统陷入停滞或出现不可预测的行为。为了解决线程饥饿问题我们可以让线程与线程之间形成同步关系。 同步在保证数据安全的前提下让线程能够按照某种特定的顺序访问临界资源从而有效避免饥饿问题。 4.2 条件变量 条件变量是利用线程间共享的全局变量进行同步的一种机制条件变量是用来描述某种资源是否就绪的一种数据化描述。其一般包含两个步骤 一个线程等待条件变量的条件成立而被挂起。另一个线程使条件成立后唤醒等待的线程。 4.3 条件变量的接口 4.3.1 初始化条件变量 我们可以使用pthread_cond_init初始化互斥量使用方法如下 函数原型int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);参数 cond需要初始化的条件变量。attr初始化条件变量的属性一般设置为 nullptr 即可。 返回值条件变量初始化成功返回0失败返回错误码。 这种调用函数接口初始化条件变量的方式我们称为动态分配除此之外我们也能使用如下的方式进行初始化我们将其称为静态分配。 pthread_cond_t cond PTHREAD_COND_INITIALIZER; 4.3.2 销毁条件变量 我们可以使用pthread_cond_destory销毁互斥量使用方法如下 函数原型int pthread_cond_destroy(pthread_cond_t *cond);参数mutex需要销毁的条件变量。返回值成功返回 0失败返回错误码。 使用 PTHREAD_COND_INITIALIZER 静态初始化的条件变量不需要销毁。 4.3.3 等待条件变量 当某个线程满足某个条件时我们就可以将其至于条件变量下等待。 函数原型int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);参数 cond需要等待的条件变量。 mutex当前线程所处临界区对应的互斥锁。 返回值成功返回 0失败返回错误码。 4.3.4 唤醒等待 在满足某个条件之后我们就可以使用以下两种即可将等待队列中的线程唤醒。 函数原型 int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond); 参数cond需要唤醒的条件变量。返回值成功返回 0失败返回错误码。 其中 pthread_cond_signal()函数用于唤醒等待队列中的第一个线程。pthread_cond_broadcast()函数用于唤醒等待队列中的全部线程。 比如我们下面创建五个线程然后将其放入等待队列最后由主线程进行唤醒。 #include iostream #include cstdio #include pthread.h #include unistd.h using namespace std; #include string pthread_mutex_t mutex; pthread_cond_t cond; void *Routine(void *args) {pthread_detach(pthread_self());string name thread to_string((uint64_t)args);while (true){pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);cout name running... endl;pthread_mutex_unlock(mutex);} } int main() {pthread_t tids[5];pthread_mutex_init(mutex, nullptr);pthread_cond_init(cond, nullptr);for (uint64_t i 0; i 5; i){pthread_create(tids i, nullptr, Routine, (void *)i);}while (true){sleep(1);pthread_cond_signal(cond);}pthread_mutex_destroy(mutex);pthread_cond_destroy(cond);return 0; }在调用font stylecolor:rgb(28, 31, 35);pthread_cond_wait/font函数时需要传入对应的互斥锁原因如下 当线程由于某些条件不满足而需要在特定条件变量下进行等待时必须释放该互斥锁。这是因为如果不释放互斥锁其他线程将无法获取该锁以进入临界区修改共享资源从而无法改变条件使等待线程被唤醒。 当该线程被唤醒后会接着执行临界区内的代码这就要求该线程必须立即获得对应的互斥锁。这样设计确保了线程在被唤醒后能够安全地访问临界区避免了多个线程同时进入临界区而导致的数据不一致和资源竞争问题。 4.4 条件变量使用规范 使用条件变量我们一般遵守以下规范如果是等待条件变量函数应该放在互斥量加锁与解锁之间因为判断条件也是一种临界资源。 pthread_mutex_lock(mutex); while (条件为假 pthread_cond_wait(cond, mutex); //修改条件 pthread_mutex_unlock(mutex);同样唤醒操作也需要类似的操作。 pthread_mutex_lock(mutex); //条件为真 pthread_cond_signal(cond); pthread_mutex_unlock(mutex);
http://www.hkea.cn/news/14452933/

相关文章:

  • 郓城菏泽网站建设巴中 网站建设
  • 信息网站建设腾讯云做wordpress太卡
  • 科技网站制作浙江省建设行政主管部门网站
  • 楼盘怎么在网站上做推广复试联系导师模板
  • 怎么做网站服务器吗公司做网站该注意哪些
  • 福州seo网站优化两支队伍建设专题网站
  • 如何快速被百度收录百度词条优化工作
  • 网站建设中高低端区别郑州建站以来
  • 合肥网站制作公司电话做网站免费搭建
  • 学校网站英文鲅鱼圈规划建设局网站
  • 1m带宽网站支持多少人同时在线学院网站建设实例
  • 某集团网站建设规划书免费html网页源代码
  • wordpress网站数据库备份凡科网注册
  • 中职网站建设溧阳市建设局网站
  • 做企业展示网站怎么把自己做的网页生成链接
  • 公司网站建立的建议网站介绍页面
  • 天津seo管理平台seo入门视频
  • 网站如何动态修改主页手机软件分类
  • 云南网官方网站烟台企业宣传片制作公司
  • 网站备案 个体工商户折叠彩页设计
  • 企业如何推广网站西乡网站建设
  • 网站上飘窗怎么做怎么做网站统计
  • 建设网站前的需求分析wordpress 判断置顶
  • 韶关做网站公司网站开发技术案例
  • 漳州正规网站建设价格企业年报网上申报系统网址
  • 网站虚拟主机销售制作网站一般多少钱
  • 专用主机方式建设网站centos建立wordpress
  • 福建设备公司网站树莓派做网站
  • 网站搭建软件d中国化工网网站建设建议
  • 运营网站软件开发模型及特点