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

做爰xo的视频网站试看关键词优化排名

做爰xo的视频网站试看,关键词优化排名,三河网站seo,北京网站建设哪家比较好目录 线程互斥 抢票的代码(已加锁) 问题:未加锁的代码为什么票数会减到了负数??? (1)数据不一致问题: (2)判断引起的!&#xff0…

目录

线程互斥

抢票的代码(已加锁) 

问题:未加锁的代码为什么票数会减到了负数???

(1)数据不一致问题:

(2)判断引起的!!!

引入线程互斥

线程互斥概念

 解决以上问题的解决方法。

创建锁的方式/互斥量的接⼝

1.定义全局的锁/静态分配

​编辑

 2.动态分配

(1)锁的初始化

(2)销毁互斥量

 互斥量加锁和解锁

代码1:对静态锁和动态锁的代码实现

延伸: 

 进程间互斥???

理解锁

​编辑 锁的原理:

(1)硬件级实现锁:关闭时钟中断,这样的话,就不会进行线程切换的情况

(2)软件级实现锁:

解释:

对于%al有很多歌,而mutex只有一个1的解释

总结:

 代码2:对锁的封装+RAII

test_Mutex.cpp

Mutex.hpp

1. RAII 的作用


线程互斥

抢票的代码(已加锁) 

// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>int ticket = 1000;void *route(void *arg)
{char *id = (char *)arg;while (1){if (ticket > 0) // 1. 判断{usleep(1000);                               // 模拟抢票花的时间printf("%s sells ticket:%d\n", id, ticket); // 2. 抢到了票ticket--;                                   // 3. 票数--}else{break;}}return nullptr;
}int main(void)
{pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

问题:未加锁的代码为什么票数会减到了负数???

(1)数据不一致问题:

在C语言中‘--’会被切换成3条汇编语言,不是原子性的,在进行汇编过程中会发生线程切换

-- 操作并不是原⼦操作,⽽是对应三条汇编指令:• load :将共享变量ticket从内存加载到寄存器中• update :更新寄存器⾥⾯的值,执⾏-1操作• store :将新值,从寄存器写回共享变量ticket的内存地址

切换,pc记录上下文,进入等待队列切换:什么时候???
1.时间片用完
2.阻塞是IO
3.sleep.....(切走)什么时候选择新:从内核态返回用户态的时候进行检查!!
陷入等待,选择新的继续执行。

拿这个图举个例子,假如ticket  == 10000,第一个线程A,通过判断进入临界区,执行完ticket ----操作,拿到ticket == 9999,准备继续执行的时候被切换了,后序线程把ticket抢到只剩1的时候,轮到线程A开始执行了,准备把ticket写会去的时候,结果,本来ticket == 1,又变成 9999 了,导致了数据不一致的问题。

(2)判断引起的!!!

举个例子,假如ticket  == 10000,第一个线程A,通过判断进入临界区,准备执行的时候被切换了,然后线程B同样如此,后序线程把ticket抢到只剩1的时候,轮到线程A和线程B开始执行了,他们开始的时候都通过判断进入临界区执行流,对ticket进行 -- 操作,结果ticket就出现负数了。 

引入线程互斥

线程互斥概念

临界资源:多线程执⾏流共享的资源就叫做临界资源

临界区:每个线程内部,访问临界资源的代码,就叫做临界区

互斥:任何时刻,互斥保证有且只有⼀个执⾏流进⼊临界区,访问临界资源,通常对临界资源起 保护作⽤

原⼦性(后⾯讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态,要么完成, 要么未完成

 解决以上问题的解决方法。

代码必须要有互斥⾏为:当代码进⼊临界区执⾏时,不允许其他线程进⼊该临界区。

• 如果多个线程同时要求执⾏临界区的代码,并且临界区没有线程在执⾏,那么只能允许⼀个线程 进⼊该临界区。

• 如果线程不在临界区中执⾏,那么该线程不能阻⽌其他线程进⼊临界区

 要做到这三点,本质上就是需要⼀把锁。Linux上提供的这把锁叫互斥量。

创建锁的方式/互斥量的接⼝


1.定义全局的锁/静态分配

原则:尽量加锁的范围粒度要细,尽量不要加太多非临界区代码


 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 

 2.动态分配

(1)锁的初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);参数:mutex:要初始化的互斥量attr:NULL
(2)销毁互斥量

销毁互斥量需要注意:

• 使⽤ PTHREAD_ MUTEX_ INITIALIZER 初始化的互斥量不需要销毁

• 不要销毁⼀个已经加锁的互斥量

• 已经销毁的互斥量,要确保后⾯不会有线程再尝试加锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);

 互斥量加锁和解锁

int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);返回值:成功返回0,失败返回错误号

代码1:对静态锁和动态锁的代码实现

// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>int ticket = 1000;
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;全局锁,静态所
pthread_mutex_t mutex;//动态锁void *route(void *arg)
{char *id = (char *)arg;while (1){// pthread_mutex_lock(&lock);pthread_mutex_lock(&mutex);if (ticket > 0) // 1. 判断{usleep(1000);                               // 模拟抢票花的时间printf("%s sells ticket:%d\n", id, ticket); // 2. 抢到了票ticket--;                                   // 3. 票数--// pthread_mutex_unlock(&lock);pthread_mutex_unlock(&mutex);}else{// pthread_mutex_unlock(&lock);pthread_mutex_unlock(&mutex);break;}}return nullptr;
}int main(void)
{pthread_mutex_init(&mutex,nullptr);pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

注意事项:

(1)全局锁不需要释放,程序运行结束,会自动释放掉

(2)动态锁: 需要初始化,和进行销毁。

(3)c++11里面的mutex的锁

#include <mutex>

std::mutex cpp_lock;

cpp_lock.lock();

cpp_lock.unlock();

延伸: 

 进程间互斥???

同理:共享内存,shm,(pthread_mutex t*)shm
对共享内存进行加锁,实际上跟对线程临界区本质是一样的。

理解锁

对临界资源进行保护:本质就是用锁,来对临界区代码进行保护

问题·1:如果有一个线程,不遵守你的规则?

-----------写bug,所有线程都必遵守

问题2:加锁之后,在临界区内部,允许线程切换吗,切换了后会怎么样(重点)!!!

答:允许切换的?!
为什么?
因为允许切换,但是我当前进程没有释放锁,我是持有锁被切换的,即便我不在,其他线程也得等我执行完代码,释放锁,其他线程才能展开锁,进入临界区。

结论:所有线程必须等我跑完,其他的线程才可以运行锁的能力本质:把并行转化成串行
 

 锁的原理:

(1)硬件级实现锁:关闭时钟中断,这样的话,就不会进行线程切换的情况

(2)软件级实现锁:

为了实现互斥锁操作,⼤多数体系结构都提供了swap或exchange指令,该指令的作⽤是把寄存器和 内存单元的数据相交换,由于只有⼀条指令,保证了原⼦性,即使是多处理器平台,访问内存的总线周 期也有先后,⼀个处理器上的交换指令执⾏时另⼀个处理器的交换指令只能等待总线周期。

解释:

(1)锁就是一种标记位,可以当做一个整数mutex
(2)%al:一个寄存器,要么记录0,要么记录1
(3)lock执行完,al里面的内容为1,则return 0表示申请所以成功,继续执行后面代码
(4)否则,就挂起等待,等待go to lock

对于%al有很多歌,而mutex只有一个1的解释

进程/线程切换:CPU内的寄存器硬件只有一套(metex = 1,只有一个),但CPU寄存器内的数据可以有多份(各个线程的%al)

如下:

CPU硬件寄存器只有一套,
但里面的数据,线程A的数据,线程B的数据...
里面的数据可以有很多份。

换句话说,如果把一个变量的内容,交换到cpu寄存区的内部,本质是:把该变量的内容,获取到当前执行流的硬件上下文中,当前CPU寄存器的硬件上下文(起始就是各个寄存器的内容)


属于:进程/线程私有的

总结:

我们用swap,exchange将内存中的变量,交换到CPU的寄存器中“本质是当前线程/进程,在获取锁,因为是交换,不是拷贝,所以1只有1份,所以谁申请到,谁的al > 1,mutex就jiaohuan谁持有锁”
锁就是mutex的内容1,谁的%al持有1,谁就持有锁。
释放锁,就是向mutex里面写1就可以了。

代码3:自动释放锁

 代码2:对锁的封装+RAII

test_Mutex.cpp

// 操作共享变量会有问题的售票系统代码
#include <iostream>
#include <mutex>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "Mutex.hpp"using namespace MutexModule;class ThreadData
{
public:ThreadData(const std::string &n, Mutex &lock): name(n),lockp(&lock){}~ThreadData() {}std::string name;Mutex *lockp;
};int ticket = 1000;
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;全局锁,静态所  ---1
// pthread_mutex_t mutex;//动态锁 ---2
// Mutex* lock = new Mutex();//模版对象 ---3,指针要动态分配内存,不然行不通
void *route(void *arg)
{// char *id = (char *)arg;// while (1)// {//     // pthread_mutex_lock(&lock);//     // pthread_mutex_lock(&mutex);//     // lock->Lock();//     if (ticket > 0) // 1. 判断//     {//         usleep(1000);                               // 模拟抢票花的时间//         printf("%s sells ticket:%d\n", id, ticket); // 2. 抢到了票//         ticket--;                                   // 3. 票数--//         // pthread_mutex_unlock(&lock);//         // pthread_mutex_unlock(&mutex);//         // lock->Unlock();//     }//     else//     {//         // pthread_mutex_unlock(&lock);//         // pthread_mutex_unlock(&mutex);//         // lock->Unlock();//         break;//     }// }// return nullptr;ThreadData* td = static_cast<ThreadData *>(arg);while (1){LockGuard guard(*(td->lockp)); // 加锁完成, RAII风格的互斥锁的实现if (ticket > 0){usleep(1000);printf("%s sells ticket:%d\n", td->name.c_str(), ticket);ticket--;}else{break;}usleep(123);}return nullptr;
}int main(void)
{// pthread_mutex_init(&mutex,nullptr);// pthread_t t1, t2, t3, t4;// pthread_create(&t1, NULL, route, (void *)"thread 1");// pthread_create(&t2, NULL, route, (void *)"thread 2");// pthread_create(&t3, NULL, route, (void *)"thread 3");// pthread_create(&t4, NULL, route, (void *)"thread 4");// pthread_join(t1, NULL);// pthread_join(t2, NULL);// pthread_join(t3, NULL);// pthread_join(t4, NULL);Mutex lock;pthread_t t1, t2, t3, t4;ThreadData *td1 = new ThreadData("thread 1", lock);pthread_create(&t1, NULL, route, td1);ThreadData *td2 = new ThreadData("thread 2", lock);pthread_create(&t2, NULL, route, td2);ThreadData *td3 = new ThreadData("thread 3", lock);pthread_create(&t3, NULL, route, td3);ThreadData *td4 = new ThreadData("thread 4", lock);pthread_create(&t4, NULL, route, td4);pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

Mutex.hpp

#pragma
#include<iostream>
#include<pthread.h>
#include<cstring>
namespace MutexModule{class Mutex{public:Mutex(){//初始化pthread_mutex_init(&mutex,nullptr);}//上锁void Lock(){int n = pthread_mutex_lock(&mutex);if(n != 0)//上锁失败{std::cerr<<"lock error:"<<strerror(n)<<std::endl;}}void Unlock(){int n = pthread_mutex_unlock(&mutex);if(n != 0)//开锁失败{std::cerr<<"unlock error:"<<strerror(n)<<std::endl;}}~Mutex(){}private:pthread_mutex_t mutex;};class LockGuard{public:LockGuard(Mutex &mutex):_mutex(mutex){_mutex.Lock();}~LockGuard(){_mutex.Unlock();}private:Mutex &_mutex;};
}

1. RAII 的作用

RAII 是一种资源管理机制,通过将资源的生命周期绑定到对象的生命周期来管理资源。在 C++ 中,对象的生命周期通常由其构造函数和析构函数控制:

  • 构造函数:负责获取资源(如加锁)。

  • 析构函数:负责释放资源(如解锁)。

在你的代码中:

cpp

复制

LockGuard guard(*td->lockp);
  • LockGuard 的构造函数会调用 td->lockp 的加锁操作,确保当前线程获取互斥锁。

  • LockGuard 对象超出作用域时(如退出 while 循环的当前迭代),其析构函数会被自动调用,从而释放互斥锁。

http://www.dtcms.com/wzjs/142591.html

相关文章:

  • 网站建设完成情况浙江网站seo
  • 北京网站建设类岗位太原seo外包服务
  • 宁夏企业网站建设中视频自媒体账号注册下载
  • 用asp做的大型网站搜索引擎推广文案
  • 新疆公司网站怎么做网店运营公司
  • 成都地区网站建设免费拓客软件排行榜
  • 用狗做头像的网站企业文化的重要性和意义
  • 网站上360 旋转的图是怎么做的成都网络优化托管公司
  • 天河做网站系统100个免费推广网站
  • 企业网站建设重要性搜索引擎营销名词解释
  • 如何维护自己的网站独立站怎么搭建
  • 微信网站设计模板下载google图片搜索
  • 北京新站优化长春网站制作
  • wap网站建设方案深圳百度竞价托管公司
  • 网络推广怎么操作福州seo网站推广优化
  • 免费给网站做seo软文广告100字
  • 大连网站建设策划杭州优化外包
  • 深圳罗湖外贸网站建设深圳企业网站制作公司
  • 公司网站免费建立seo渠道
  • 陕西建设网官网登录seo优化方式
  • 门户网站的流程互联网推广引流
  • 深圳网站建设响应式西安网站seo外包
  • 手机微网站怎么做查图百度识图
  • 网站建设优点百度客户服务中心
  • 各大房产网站微指数
  • 自己怎么做卡密网站网上营销型网站
  • 很大气的网站 营销无锡网站服务公司
  • 网站建设的报告分析河南最近的热搜事件
  • wordpress检查全站链接淘宝seo优化是什么意思
  • 网站做seo有什么作用武汉服装seo整站优化方案