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

客户问 你们网站怎么做的seo成都

客户问 你们网站怎么做的,seo成都,郑州网站建设公司排行榜,什么是网站建设方案书Linux知识点 – Linux多线程#xff08;四#xff09; 文章目录 Linux知识点 -- Linux多线程#xff08;四#xff09;一、线程池1.概念2.实现3.单例模式的线程池 二、STL、智能指针和线程安全1.STL的容器是否是线程安全的2.智能指针是否是线程安全的 三、其他常见的各种锁…Linux知识点 – Linux多线程四 文章目录 Linux知识点 -- Linux多线程四一、线程池1.概念2.实现3.单例模式的线程池 二、STL、智能指针和线程安全1.STL的容器是否是线程安全的2.智能指针是否是线程安全的 三、其他常见的各种锁四、读者写者问题1.读写锁2.读写锁接口 一、线程池 1.概念 一种线程使用模式。线程过多会带来调度开销进而影响缓存局部性和整体性能。而线程池维护着多个线程等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 预先申请资源用空间换时间预先申请一批线程任务到来就处理线程池就是一个生产消费模型 2.实现 thread.hpp 线程封装 #pragma once#includeiostream #includestring #includefunctional #includecstdiotypedef void* (*fun_t)(void*); // 定义函数指针类型后面回调class ThreadData // 线程信息结构体 { public:void* _args;std::string _name; };class Thread { public:Thread(int num, fun_t callback, void* args): _func(callback){char nameBuffer[64];snprintf(nameBuffer, sizeof(nameBuffer), Thread-%d, num);_name nameBuffer;_tdata._args args;_tdata._name _name;}void start() // 创建线程{pthread_create(_tid, nullptr, _func, (void*)_tdata); // 直接将_tdata作为参数传给回调函数}void join() // 线程等待{pthread_join(_tid, nullptr);}std::string name(){return _name;}~Thread(){}private:std::string _name;fun_t _func;ThreadData _tdata;pthread_t _tid; };lockGuard.hpp 锁的封装构建对象时直接加锁对象析构时自动解锁 #pragma once#include iostream #include pthread.hclass Mutex { public:Mutex(pthread_mutex_t *mtx): _pmtx(mtx){}void lock(){pthread_mutex_lock(_pmtx);}void unlock(){pthread_mutex_unlock(_pmtx);}~Mutex(){}private:pthread_mutex_t *_pmtx; };class lockGuard { public:lockGuard(pthread_mutex_t *mtx): _mtx(mtx){_mtx.lock();}~lockGuard(){_mtx.unlock();} private:Mutex _mtx; };log.hpp #pragma once#includeiostream #includecstdio #includecstdarg #includectime #includestring//日志级别 #define DEBUG 0 #define NORMAL 1 #define WARNING 2 #define ERROR 3 #define FATAL 4const char* gLevelMap[] {DEBUG,NORMAL,WARNING,ERROR,FATAL };#define LOGFILE ./threadpool.log//完整的日志功能至少需要日志等级 时间 支持用户自定义日志内容文件行文件名void logMessage(int level, const char* format, ...) { #ifndef DEBUG_SHOWif(level DEBUG) return; #endifchar stdBuffer[1024];//标准部分time_t timestamp time(nullptr);snprintf(stdBuffer, sizeof(stdBuffer), [%s] [%ld] , gLevelMap[level], timestamp);char logBuffer[1024];//自定义部分va_list args;va_start(args, format);vsnprintf(logBuffer, sizeof(logBuffer), format, args);va_end(args);FILE* fp fopen(LOGFILE, a);fprintf(fp, %s %s\n, stdBuffer, logBuffer);fclose(fp); }注 1提取可变参数 使用宏来提取可变参数 将可变参数格式化打印到对应地点 format是打印的格式 2条件编译 条件编译不想调试的时候就不加DEBUG宏不打印日志信息 -D在命令行定义宏 threadPool.hpp 线程池封装 #include thread.hpp #include vector #include queue #include unistd.h #include log.hpp #include Task.hpp #include lockGuard.hppconst int g_thread_num 3;template class T class ThreadPool { public:pthread_mutex_t *getMutex(){return _lock;}bool isEmpty(){return _task_queue.empty();}void waitCond(){pthread_cond_wait(_cond, _lock);}T getTask(){T t _task_queue.front();_task_queue.pop();return t;}ThreadPool(int thread_num g_thread_num): _num(thread_num){pthread_mutex_init(_lock, nullptr);pthread_cond_init(_cond, nullptr);for (int i 1; i _num; i){_threads.push_back(new Thread(i, routine, this));// 线程构造传入的this指针是作为ThreadData结构体的参数的ThreadData结构体才是routine回调函数的参数}}void run(){for (auto iter : _threads){iter-start();logMessage(NORMAL, %s %s, iter-name().c_str(), 启动成功);}}// 消费过程线程调用回调函数取任务就是所谓的消费过程访问了临界资源需要加锁static void *routine(void *args){ThreadData *td (ThreadData *)args;ThreadPoolT *tp (ThreadPoolT *)td-_args; // 拿到this指针while (true){T task;{lockGuard lockguard(tp-getMutex());while (tp-isEmpty()){tp-waitCond();}// 读取任务task tp-getTask();// 任务队列是共享的将任务从共享空间拿到私有空间}task(td-_name); // 处理任务}}void pushTask(const T task){lockGuard lockguard(_lock); // 访问临界资源需要加锁_task_queue.push(task);pthread_cond_signal(_cond); // 推送任务后发送信号让进程处理}~ThreadPool(){for (auto iter : _threads){iter-join();delete iter;}pthread_mutex_destroy(_lock);pthread_cond_destroy(_cond);}private:std::vectorThread * _threads; // 线程池int _num;std::queueT _task_queue; // 任务队列pthread_mutex_t _lock; // 锁pthread_cond_t _cond; // 条件变量 };注 1如果回调函数routine放在thread类里面由于成员函数会默认传this指针因此参数识别的时候可能会出错所以需要设置成静态成员 2如果设置成静态类内方法这个函数只能使用静态成员而不能使用其他类内成员 可以让routine函数拿到整体对象在构造线程的时候routine的参数传入this指针 在构造函数的初始化列表中是参数的初始化在下面的函数体中是赋值的过程因此在函数体中对象已经存在了就可以使用this指针了 3类内公有接口让静态成员函数routine通过this指针能够访问类内成员 testMain.cc #includethreadPool.hpp #includeTask.hpp #includectime #includecstdlib #includeiostream #includeunistd.hint main() {srand((unsigned long)time(nullptr) ^ getpid());ThreadPoolTask* tp new ThreadPoolTask();tp-run();while(true){//生产的时候只做任务要花时间int x rand()%100 1;usleep(7756);int y rand()%30 1;Task t(x, y, [](int x, int y)-int{return x y;});logMessage(DEBUG, 制作任务完成%d%d?, x, y);//推送任务到线程池中tp-pushTask(t);sleep(1);}return 0; }运行结果 3.单例模式的线程池 threadPool.hpp #include thread.hpp #include vector #include queue #include unistd.h #include log.hpp #include Task.hpp #include lockGuard.hppconst int g_thread_num 3;template class T class ThreadPool { public:pthread_mutex_t *getMutex(){return _lock;}bool isEmpty(){return _task_queue.empty();}void waitCond(){pthread_cond_wait(_cond, _lock);}T getTask(){T t _task_queue.front();_task_queue.pop();return t;}//单例模式线程池懒汉模式 private://构造函数设为私有ThreadPool(int thread_num g_thread_num): _num(thread_num){pthread_mutex_init(_lock, nullptr);pthread_cond_init(_cond, nullptr);for (int i 1; i _num; i){_threads.push_back(new Thread(i, routine, this));// 线程构造传入的this指针是作为ThreadData结构体的参数的ThreadData结构体才是routine回调函数的参数}}ThreadPool(const ThreadPoolT other) delete;const ThreadPoolT operator(const ThreadPoolT other) delete;public://创建单例对象的类内静态成员函数static ThreadPoolT* getThreadPool(int num g_thread_num){//在这里再加上一个条件判断可以有效减少未来必定要进行的加锁检测的问题//拦截大量的在已经创建好单例的时候剩余线程请求单例而直接申请锁的行为if(nullptr _thread_ptr){//加锁lockGuard lockguard(_mutex);//未来任何一个线程想要获取单例都必须调用getThreadPool接口//一定会存在大量的申请锁和释放锁的行为无用且浪费资源if(nullptr _thread_ptr){_thread_ptr new ThreadPoolT(num);}}return _thread_ptr;}void run(){for (auto iter : _threads){iter-start();logMessage(NORMAL, %s %s, iter-name().c_str(), 启动成功);}}// 消费过程线程调用回调函数取任务就是所谓的消费过程访问了临界资源需要加锁static void *routine(void *args){ThreadData *td (ThreadData *)args;ThreadPoolT *tp (ThreadPoolT *)td-_args; // 拿到this指针while (true){T task;{lockGuard lockguard(tp-getMutex());while (tp-isEmpty()){tp-waitCond();}// 读取任务task tp-getTask();// 任务队列是共享的将任务从共享空间拿到私有空间}task(td-_name); // 处理任务}}void pushTask(const T task){lockGuard lockguard(_lock); // 访问临界资源需要加锁_task_queue.push(task);pthread_cond_signal(_cond); // 推送任务后发送信号让进程处理}~ThreadPool(){for (auto iter : _threads){iter-join();delete iter;}pthread_mutex_destroy(_lock);pthread_cond_destroy(_cond);}private:std::vectorThread * _threads; // 线程池int _num;std::queueT _task_queue; // 任务队列static ThreadPoolT* _thread_ptr;static pthread_mutex_t _mutex;pthread_mutex_t _lock; // 锁pthread_cond_t _cond; // 条件变量 };//静态成员在类外初始化 templateclass T ThreadPoolT* ThreadPoolT::_thread_ptr nullptr;templateclass T pthread_mutex_t ThreadPoolT::_mutex PTHREAD_MUTEX_INITIALIZER;多线程同时调用单例过程由于创建过程是非原子的有可能被创建多个对象是非线程安全的 需要对创建对象的过程加锁就可以保证在多线程场景当中获取单例对象 但是未来任何一个线程想调用单例对象都必须调用这个成员函数就会存在大量申请和释放锁的行为 可以在之间加一个对单例对象指针的判断若不为空就不进行对象创建 testMain.cc #includethreadPool.hpp #includeTask.hpp #includectime #includecstdlib #includeiostream #includeunistd.hint main() {srand((unsigned long)time(nullptr) ^ getpid());//ThreadPoolTask* tp new ThreadPoolTask();//tp-run(); ThreadPoolTask::getThreadPool()-run();//创建单例对象while(true){//生产的时候只做任务要花时间int x rand()%100 1;usleep(7756);int y rand()%30 1;Task t(x, y, [](int x, int y)-int{return x y;});logMessage(DEBUG, 制作任务完成%d%d?, x, y);//推送任务到线程池中ThreadPoolTask::getThreadPool()-pushTask(t);sleep(1);}return 0; }运行结果 二、STL、智能指针和线程安全 1.STL的容器是否是线程安全的 不是 原因是, STL的设计初衷是将性能挖掘到极致而一旦涉及到加锁保证线程安全会对性能造成巨大的影响 而且对于不同的容器加锁方式的不同性能可能也不同(例如hash表的锁表和锁桶)。 因此STL默认不是线程安全。如果需要在多线程环境下使用往往需要调用者自行保证线程安全。 2.智能指针是否是线程安全的 对于unique_ ptr由于只是在当前代码块范围内生效因此不涉及线程安全问题 对于shared_ptr多个对象需要共用一个引用计数变量所以会存在线程安全问题.但是标准库实现的时候考虑到了这个问题,基于原子操作(CAS)的方式保证shared_ptr 能够高效,原子的操作弓|用计数 三、其他常见的各种锁 悲观锁在每次取数据时总是担心数据会被其他线程修改所以会在取数据前先加锁(读锁,写锁行锁等) ,当其他线程想要访问数据时被阻塞挂起乐观锁每次取数据时候总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作 CAS操作当需要更新数据时判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败失败则重试一般是一个自旋的过程即不断重试自旋锁 临界资源就绪的时间决定了线程等待的策略 不断检测资源是否就绪就是自旋轮询检测 自旋锁本质就是通过不断检测锁状态来检测资源是否就绪的方案 互斥锁是检测到资源未就绪就挂起线程 临界资源就绪的时间决定了使用哪种锁 四、读者写者问题 1.读写锁 在编写多线程的时候有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少相比较改写它们读的机会反而高的多。通常而言在读的过程中往往伴随着查找的操作,中间耗时长。给这种代码段加锁会极大地降低我们程序的效率。那么有没有一种方法可以专门]处理这种多读少写的情况呢有那就是读写锁。 读者写者模型与生产消费模型的本质区别 生产消费模型中消费者会取走数据而读者写者模型中读者不会取走数据 读锁的优先级高 2.读写锁接口 初始化 读者加锁 写者加锁 生产消费模型中生产者和消费者的地位是对等的这样才能达到最高效的状态 而读写者模型中写者只有在读者全部退出的时候才能写是读者优先的这样就会发生写者饥饿问题 读者写者问题中读锁的优先级高是因为这种模型的应用场景为数据的读取频率非常高而被修改的频率特别低这样有助于提升效率
http://www.w-s-a.com/news/963744/

相关文章:

  • 企业做网站需要多少钱企业资质查询系统官网
  • 网站建设需要知识百度统计数据
  • 自已如何做网站建设通网站会员共享密码
  • 做网站学习什么wordpress 文件夹
  • 前端移动网站开发wordpress图文混排
  • 企业网站建站那种好商城类网站怎么优化
  • 手机微网站怎么制作的网上找设计师
  • 网站建设包括哪些方面学校网站 建设
  • 贵阳网站优化公司建筑设计师用什么软件
  • 网站建设的小说静态网页模板免费网站
  • 芜湖建设厅官方网站wordpress自动设置缩略图
  • 推荐网站网页湛江网站建设哪家优惠多
  • 传奇网站免费空间网店装修店面
  • 网站改版 重新收录湖南建筑信息一体化管理平台
  • 可以做直播卖产品的网站陕西省建设银行网站
  • 搭建网站的英语seo优化专员招聘
  • 做网站深紫色搭配什么颜色网站的在线支付怎么做
  • 中国最大网站建设公司长沙专业做网站公司哪家好
  • 金峰辉网站建设菏泽财富中心网站建设
  • 怎么做网站站长视频企业网站开发意义
  • 网站创建多少钱商标自助查询系统官网
  • 免费做App和网站的平台广州做网站推广的公司
  • 衡水做网站推广的公司wordpress相册滑动
  • 不用域名也可以做网站公司网站建设制作难么
  • 学做网站培训机构wordpress 图片拉伸
  • 成都捕鱼网站建设wordpress自定义文章类别
  • wordpress网站怎么加速湖北网站建设企业
  • 迁安做网站中的cms开发南平网站建设公司
  • 肥西县住房和城乡建设局网站代驾系统定制开发
  • 网站建设明细报价表 服务器qq是哪家公司的产品