线程的同步
目录
引入
认识条件变量
快速认识接口编辑
认识条件变量编辑
测试代码编辑
生产消费模型
为何要使用生产者消费者模型
理解
编写生产消费模型
BlockingQueue
单生产单消费
多生产多消费
引入
同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步
认识条件变量
条件变量是C语言中使用POSIX线程(pthread)库实现线程同步的一种机制。它允许线程在某个条件满足之前进入等待状态,直到其他线程通知它们该条件已改变。
快速认识接口
认识条件变量
测试代码
一次唤醒一个:
一次全部唤醒:
#include <iostream>
#include <string>
#include<unistd.h>
#include <pthread.h>
using namespace std;
pthread_mutex_t gmutex=PTHREAD_MUTEX_INITIALIZER;//定义一把全局的锁
pthread_cond_t gcond=PTHREAD_COND_INITIALIZER;//全局条件变量
int num = 5;void* waitt(void*agv){string name=static_cast<const char*>(agv);while(true){pthread_mutex_lock(&gmutex);//加锁 pthread_cond_wait(&gcond,&gmutex);//条件变量等待,这里就是线程等待的位置usleep(10000);cout<<"i am: "<<name<<endl;pthread_mutex_unlock(&gmutex);//解锁}
}
int main()
{pthread_t threads[num];for (int i = 0; i < num; i++)//创建线程{char *name = new char[1024]; // 用来动态分配一个大小为1024字节的字符数组,并将其地址赋给指针namesnprintf(name, 1024, "thread-%d", i + 1); // 注意不用sizeof了因为sizeof(name)为地址字节不是大小了pthread_create(threads + i, nullptr, waitt, (void *)name);usleep(10000);}sleep(1);while(true){//唤醒pthread_cond_broadcast(&gcond);//全部唤醒//pthread_cond_signal(&gcond);//一次一个cout<<"唤醒一个线程......"<<endl;sleep(2);//唤醒的慢些}for (int i = 0; i < num; i++)//线程等待{ pthread_join(threads[i],nullptr);}
}
生产消费模型
为何要使用生产者消费者模型
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
理解
生产消费模型通常是多执行流并发的模型------多个执行流之间怎么进行互斥同步之间如何协同的模型;
供应商和消费者就是线程,超市就是一段内存,方便面就是数据;
未来生产线程将数据放到缓存中,消费者需要的时候从缓存拿;
思考切入点:“321”原则
1. 一个交易场所(特定数据结构形式存在的一段内存空间)
2. 两种角色(生产角色,消费角色)--生产线程,消费线程
3. 3种关系(生产和生产(竞争关系-互斥),消费和消费(互斥--资源少时就竞争了),生产和消费(互斥--生产者在向缓冲区写入数据时,消费者不能同时从缓冲区中读取数据,以免读取错误数据&&同步--消费者消费数据导致没数据就通知生产者放数据))
实现生产消费模型本质就是:通过代码实现321原则,用锁和条件变量(或其他方式)来实现三种关系!
编写生产消费模型
BlockingQueue
在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程 操作时会被阻塞)
那么可以想到进程间通信时用的管道,一个向管道里写另一个从管道里读。管道如果满了,写进程就要阻塞,如果空了,读进程就要阻塞。管道就是典型的阻塞队列--生产消费模型,只不过使用进程来代替;
单生产单消费
那么生产和生产以及消费和消费之间的关系就不用维护了;
简单测试代码
blockqueue.hpp:
#pragma once #include <iostream> #include <string> #include <queue> //使用stl的queue #include <pthread.h>using namespace std; const static int defaultcap = 5;template <typename T> // 引入模板 class blockqueue { private:bool full(){return _block_queue.size() == _max_cap;}bool empty(){return _block_queue.empty();}public:blockqueue(int cap = defaultcap) : _max_cap(cap){pthread_mutex_init(&_mutex, nullptr); // 初始化锁pthread_cond_init(&_p_cond, nullptr); // 初始条件变量pthread_cond_init(&_c_cond, nullptr); // 初始条件变量}void Pop(T *out){ // 把队列中的数据带出去pthread_mutex_lock(&_mutex); // 用的同一把锁,互斥关系while (empty()){pthread_cond_wait(&_c_cond, &_mutex); // 在该条件变量下等待}// 此时走到这里,1.没有满 || 2.被唤醒了*out = _block_queue.front();_block_queue.pop(); // 拿出数据了pthread_mutex_unlock(&_mutex);pthread_cond_signal(&_p_cond); // 消费一个了那么你就可以生产了,队列有空间了// signal放在unlock之前还是之后都是可以的}// 那么唤醒可以由他们两个互相唤醒互相void equeue(const T &in){ // 入队列pthread_mutex_lock(&_mutex); // 加锁防止向临界区放数据被打扰while (full()){ // 判断是否为满了// 满了不能生产,必须等待// 此时在临界区里,加锁和解锁之间// pthread_cond_wait在被调用的时候:除了让自己继续排队等待,还会自己释放传入的锁// 函数返回的时候,不就还在临界区么?那么被返回时必须先参与锁的竞争,重新加上锁,该函数才被返回;那么返回时就有锁了pthread_cond_wait(&_p_cond, &_mutex); // 在该条件变量下等待}// 此时走到这里,1.没有满 || 2.被唤醒了_block_queue.push(in); // 生产到阻塞队列里,此时没解锁所以一定至少有一个数据在队列里pthread_mutex_unlock(&_mutex);pthread_cond_signal(&_c_cond); // 生产一个了那么你就可以消费了// 让消费者消费}~blockqueue(){pthread_mutex_destroy(&_mutex); // 将锁销毁pthread_cond_destroy(&_p_cond); // 将局部条件变量销毁pthread_cond_destroy(&_c_cond); // 将局部条件变量销毁}private:queue<T> _block_queue; // 临界资源int _max_cap; // 队列最大容量pthread_mutex_t _mutex; // 锁pthread_cond_t _p_cond; // 为生产者提供的条件变量pthread_cond_t _c_cond; // 为消费者提供的条件变量 };
main.cc:
构建数据(int)
#include"blockqueue.hpp" #include<pthread.h> #include<ctime> #include<unistd.h>void*consumer(void*agv){blockqueue<int>* bq=static_cast<blockqueue<int>* >(agv);while(true){sleep(2);//消费的慢些//1.拿数据int date=0;bq->Pop(&date);//拿//2.处理数据cout<<"consumer-> "<<date<<endl;} } void*productor(void*agv){srand(time(nullptr)^getpid());//增加随机性blockqueue<int>* bq=static_cast<blockqueue<int>* >(agv);//两个线程看到同一个阻塞队列while(true){//1.构建数据int date=rand()%10+1;//[1,10]//2.生产数据bq->equeue(date);//入cout<<"producter-> "<<date<<endl;} }int main(){blockqueue<int>* bq=new blockqueue<int>();//使用int类型pthread_t c,p;pthread_create(&c,nullptr,consumer,bq); pthread_create(&p,nullptr,productor,bq); pthread_join(c,nullptr);pthread_join(p,nullptr);return 0; }// #include <iostream> // #include <string> // #include<unistd.h> // #include <pthread.h> // using namespace std; // pthread_mutex_t gmutex=PTHREAD_MUTEX_INITIALIZER;//定义一把全局的锁 // pthread_cond_t gcond=PTHREAD_COND_INITIALIZER;//全局条件变量 // int num = 5;// void* waitt(void*agv){ // string name=static_cast<const char*>(agv); // while(true){ // pthread_mutex_lock(&gmutex);//加锁 // pthread_cond_wait(&gcond,&gmutex);//条件变量等待,这里就是线程等待的位置 // usleep(10000); // cout<<"i am: "<<name<<endl; // pthread_mutex_unlock(&gmutex);//解锁 // } // } // int main() // { // pthread_t threads[num]; // for (int i = 0; i < num; i++)//创建线程 // { // char *name = new char[1024]; // 用来动态分配一个大小为1024字节的字符数组,并将其地址赋给指针name // snprintf(name, 1024, "thread-%d", i + 1); // 注意不用sizeof了因为sizeof(name)为地址字节不是大小了 // pthread_create(threads + i, nullptr, waitt, (void *)name); // usleep(10000); // } // sleep(1); // while(true){//唤醒 // pthread_cond_broadcast(&gcond);//全部唤醒 // //pthread_cond_signal(&gcond);//一次一个 // cout<<"唤醒一个线程......"<<endl; // sleep(2);//唤醒的慢些 // }// for (int i = 0; i < num; i++)//线程等待 // { // pthread_join(threads[i],nullptr); // } // }
main.cc:
构建任务(task--类)
#include"blockqueue.hpp" #include"task.hpp" #include<pthread.h> #include<ctime> #include<unistd.h>void*consumer(void*agv){blockqueue<task>* bq=static_cast<blockqueue<task>* >(agv);while(true){sleep(2);//消费的慢些//1.拿数据task t;//无参构造bq->Pop(&t);//拿//2.处理数据t.excute();cout<<"consumer-> "<<t.result()<<endl;} } void*productor(void*agv){srand(time(nullptr)^getpid());//增加随机性blockqueue<task>* bq=static_cast<blockqueue<task>* >(agv);//两个线程看到同一个阻塞队列while(true){//1.构建数据int x=rand()%10+1;//[1,10]usleep(10000);//让两个数据尽量不一样,休眠一段时间int y=rand()%10+1;//[1,10]//2.生产数据task t(x,y);//有参构造bq->equeue(t);//入cout<<"producter-> "<<t.debug()<<endl;} }int main(){blockqueue<task>* bq=new blockqueue<task>();pthread_t c,p;pthread_create(&c,nullptr,consumer,bq); pthread_create(&p,nullptr,productor,bq); pthread_join(c,nullptr);pthread_join(p,nullptr);return 0; }
task.hpp:
#pragma once #include "blockqueue.hpp" using namespace std; class task { public:task() {}task(int x, int y) : _x(x), _y(y){}void excute(){_result = _x + _y;}string debug(){string msg = to_string(_x) + "+" + to_string(_y) + "=?";return msg;}string result(){string msg = to_string(_x) + "+" + to_string(_y) +"="+ to_string(_result);return msg;}~task(){}private:int _x;int _y;int _result; };
main.cc:
仿函数
#include "blockqueue.hpp" #include "task.hpp" #include <pthread.h> #include <ctime> #include <unistd.h>void *consumer(void *agv) {blockqueue<task_t> *bq = static_cast<blockqueue<task_t> *>(agv);while (true){sleep(2); task_t t;bq->Pop(&t);// 从队列中取出并执行任务t();// 执行任务} } void *productor(void *agv) {srand(time(nullptr) ^ getpid()); // 增加随机性blockqueue<task_t> *bq = static_cast<blockqueue<task_t> *>(agv); // 两个线程看到同一个阻塞队列while (true){bq->equeue(download); cout<<"productor->download "<<endl;} }int main() {blockqueue<task_t> *bq = new blockqueue<task_t>();pthread_t c, p;pthread_create(&c, nullptr, consumer, bq);pthread_create(&p, nullptr, productor, bq);pthread_join(c, nullptr);pthread_join(p, nullptr);return 0; }
task.hpp:
#pragma once #include<iostream> #include<functional> using namespace std;using task_t=function<void()>;//等价于typedef function<void()> task_t; //定义了一个新的类型别名 task_t,它表示一个接受无参数并返回 void 的函数类型void download(){cout<<"i am a download task"<<endl; }
多生产多消费
多生产多消费直接复用上面代码即可;
那么针对生产者不仅仅要将任务放到超市(花费时间),他还要产生任务也要花费时间;
那么针对消费者不仅仅要从超市拿到任务(花费时间),这个任务属于消费者自己了,那么他还要处理任务也要花费时间;
那么我们就不能仅仅只考虑放任务到超市叫生产,拿任务叫消费;
那么一个生产商再放任务的时候,那么其他生产商有没有正在生产任务呢。
那么放任务和产生任务就并发了;
那么一个消费者再拿任务的时候,那么其他消费者有没有早都获取了任务正在处理任务呢。
那么拿任务和处理任务就并发了;
如果未来消费处理任务花费时间比较久但是生产任务比较快,那么可以单生产多消费,那么生产任务的时候,一方面有线程在获取另一方面在并发处理任务;
如果未来生产任务花费时间比较久但是消费任务比较快,那么可以多生产单消费;
都很慢就可以多生产多消费;
问题:为什么等待就要在加锁和解锁之间等待呢?
无论是生产者还是消费者都必须先检测资源的状态,对于生产和消费来说他们要访问公共资源,它不知道资源的条件是否满足。对于生产者来说希望队列有空间,对于消费者来说希望队列有数据。可是对于他们来说他们并不知道,只有他们查一次才知道,而查这一行为本身就是访问,就决定了查之前就要加锁,并且检测可能满足可能不满足,注定了必须在临界区里等待因为判定结果是在临界区里的;
相关文章:
线程的同步
目录 引入 认识条件变量 快速认识接口编辑 认识条件变量编辑 测试代码编辑 生产消费模型 为何要使用生产者消费者模型 理解 编写生产消费模型 BlockingQueue 单生产单消费 多生产多消费 引入 同步:在保证数据安全的前提下,让线程…...
【启明智显分享】ZX7981PG/ZX7981PM融入官方OpenWrt,启明智显SDK/官方OpenWrt任由选择!
好消息!好消息!启明智显ZX7981PG和ZX7981PM正式融入官方 OpenWrt 的大家庭啦!现在开发者不仅可以基于启明智显的SDK进行二次开发,还可以直接应用官方OpenWrt以及我们的开源资料进行开发! 借助OpenWrt的强大生态&…...
如何用java发送包含表格形式的邮件
问题: 如何用java发送包含表格形式的邮件? 方法: 发用freemaker工具来替换html的表格变量,从而动态生成了html。然后再发送这个html格式(不能用纯文本)文本即可。 优化流程: 1、准备模板&#x…...
讲个故事:关于一次接口性能优化的心里路程
这是一个程序猿写的第一个故事,请各位懂行的客官静下心来,慢慢品读。就知道我为什么要单独写一个文章来记录这次过程了,因为实在是太坎坷了...... 背景介绍 近期项目投产时遇到一个问题,投产后在验证时发现大部分用户系统登…...
Centos7升级到openssh9.9
openssh9.9 是2024.9.20出的最新版ssh。因为客户扫描出一大堆centos7的漏洞,全是这个openssh的,好多补丁,所以索性升级到最新版。 需要自己制作rpm包,这个我是不懂,照这个来: Linux服务器升级openssh9.9最…...
使用 STM32F407 串口实现 485 通信
准备工作 了解485通信基本概念与原理:RS485通信详解_485通讯de接什么口-CSDN博客 安装编译软件:keil uVision 5.6 软件资料:STM32CubeF4 固件包,正点原子RS485通信例程 参考视频:第26讲 基础篇-新建H…...
基于NERF技术重建学习笔记
NeRF(Neural Radiance Fields)是一种用于3D场景重建的神经网络模型,能够从2D图像生成逼真的3D渲染效果。它将场景表征为一个连续的5D函数,利用了体积渲染和神经网络的结合,通过学习光线穿过空间时的颜色和密度来重建场…...
webView 支持全屏播放
webView 支持全屏播放 直接上代码 public class CustomFullScreenWebViewClient extends WebChromeClient {WebView webView;Context context;/*** 视频全屏参数*/protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS new FrameLayout.LayoutParams(ViewG…...
QGIS之三十二DEM地形导出三维模型gltf
效果 1、准备数据 (1)dem.tif (2)dom.tif 2、qgis加载dem和dom数据 3、安装插件 插件步骤可以参考这篇文章 QGIS之二十四安装插件 安装了Qgis2threejs插件,结果...
【python爬虫】携程旅行景点游客数据分析与可视化
一.选题背景 随着旅游业的快速发展,越来越多的人选择通过互联网平台预订旅行产品,其中携程网作为国内领先的在线旅行服务提供商,拥有大量的旅游产品和用户数据。利用爬虫技术可以获取携程网上各个景点的游客数据,包括游客数量、游…...
python实现onvif协议下控制摄像头变焦,以及融合人形识别与跟踪控制
#1024程序员节 | 征文# 这两天才因为项目需要,对网络摄像头的视频采集以及实现人形识别与跟踪技术。对于onvif协议自然起先也没有任何的了解。但是购买的摄像头是SONY网络头是用在其他地方的。因为前期支持探究项目解决方案,就直接拿来做demo测试使用。 …...
【Vue】Vue3.0(十四)接口,泛型和自定义类型的概念及使用
上篇文章: 【Vue】Vue3.0(十三)中标签属性ref(加在普通标签上、加在组件标签上)、局部样式 🏡作者主页:点击! 🤖Vue专栏:点击! ⏰️创作时间&…...
【C++】红黑树万字详解(一文彻底搞懂红黑树的底层逻辑)
目录 00.引入 01.红黑树的性质 02.红黑树的定义 03.红黑树的插入 1.按照二叉搜索树的规则插入新节点 2.检测新节点插入后,是否满足红黑树的性质 1.uncle节点存在且为红色 2.uncle节点不存在 3.uncle节点存在且为黑色 04.验证红黑树 00.引入 和AVL树一样&am…...
开源FluentFTP实操,操控FTP文件
概述:通过FluentFTP库,轻松在.NET中实现FTP功能。支持判断、创建、删除文件夹,判断文件是否存在,实现上传、下载和删除文件。简便而强大的FTP操作,提升文件传输效率。 在.NET中,使用FluentFTP库可以方便地…...
论文解读 | ECCV2024 AutoEval-Video:一个用于评估大型视觉-语言模型在开放式视频问答中的自动基准测试...
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 点击 阅读原文 观看作者讲解回放! 作者简介 陈修元,上海交通大学清源研究院硕士生 概述 总结来说,我们提出了一个新颖且具有挑战性的基准测试AutoEvalVideo,用于全…...
postgresql14主从同步流复制搭建
1. 如果使用docker搭建请移步 Docker 启动 PostgreSQL 主从架构:实现数据同步的高效部署指南_docker安装postgresql主从同步-CSDN博客 2. 背景 pgsql版本:PostgreSQL 14.13 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4…...
企业信息化管理中的数据集成方案:销售出库单对接
企业信息化管理中的数据集成方案:销售出库单对接 销售出库单旺店通→金蝶:高效数据集成案例分享 在企业信息化管理中,数据的高效流动和准确对接是实现业务流程自动化的关键。本文将聚焦于一个具体的系统对接集成案例:如何将旺店通…...
3.cpp基本数据类型
cpp基本数据类型 1.cpp基本数据类型 1.cpp基本数据类型 C基本数据类型和C语言的基本数据类型差不多 注意bool类型:存储真值 true 或假值 false,C语言编译器C99以上支持。 C语言的bool类型:要添加 #include <stdbool.h>头文件 #includ…...
MCK主机加固与防漏扫的深度解析
在当今这个信息化飞速发展的时代,网络安全成为了企业不可忽视的重要议题。漏洞扫描,简称漏扫,是一种旨在发现计算机系统、网络或应用程序中潜在安全漏洞的技术手段。通过自动化工具,漏扫能够识别出系统中存在的已知漏洞࿰…...
《软件估算之原始功能点:精准度量软件规模的关键》
《软件估算之原始功能点:精准度量软件规模的关键》 一、软件估算的重要性与方法概述二、原始功能点的构成要素(一)数据功能(二)事务功能 三、原始功能点的估算方法(一)功能点分类估算࿰…...
序列化与反序列化
序列化和反序列化是数据处理中的两个重要概念,它们在多种场景下都非常有用,尤其是在分布式系统、网络通信、持久化存储等方面。下面是对这两个概念的详细解释: 序列化(Serialization) 定义:序列化是将对象…...
安装nginx实现多ip访问多网站
[rootlocalhost ~]# systemctl stop firewalld 关防火墙 [rootlocalhost ~]# setenforce 0 关selinux [rootlocalhost ~]# mount /dev/sr0 /mnt 挂载点 [rootlocalhost ~]# dnf install nginx -y 安装nginx [rootlocalhost ~]# nmtui 当前主机添加多地址 [rootlocal…...
每日回顾:简单用C写 冒泡排序、快速排序
冒泡排序 冒泡排序(Bubble Sort)是一种简单的排序算法,它通过重复遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复进行直到没有再需要交换,也就是说该数列已…...
前端_007_Axios库
文章目录 配置响应结构拦截器 引入: 官网: https://www.axios-http.cn/ 一句话简介:浏览器里基于XmlHttpRequests,node.js里基于http模块封装的网络请求库,使用非常方便 //通用例子axios({method:post,url: request…...
NAND FLASH 与 SPI FLASH
面试的时候再有HR针对从数据手册开始做,直接说明:例如RK3588等高速板设计板都有设计指导书,基本把对应的DDR等型号和布局规范都说明,或者DCDC电路直接给一个典型设计原理图,或者BMS更加经典,原理图给的是最…...
QTCreator打不开双击没反应
问题描述 双击后进程里显示有,当过几秒直接消失 解决 找到C\用户\AppData\Roaming\QtProject,删除目录下QtCreator.ini文件(这会重置QtCreator的默认设置),再打开QtCreator时会自动生成对应于默认设置的QtCreator.ini文件&…...
vue npm run ...时 报错-系统找不到指定的路径
vue项目修改时,不知道那一步操作错误了,运行npm run …时报错 系统找不到指定的路径,对此进行记录一下! 解决方法: 1、执行 npm install 命令,重新下载模块 2、根据下方提示执行 npm fund 查看详细信息 …...
54页可编辑PPT | 大型集团企业数据治理解决方案
这份PPT是关于大型集团企业数据治理的全面解决方案,它详细介绍了数据治理的背景、需求、管理范围、框架、解决思路,以及数据治理在实际操作中的关键步骤。内容涵盖了数据架构、数据质量、数据应用等方面的问题,并提出了数据资产透视、智能搜索…...
STM32嵌入式移植GmSSL库
前言 最近在做一个换电柜的项目,需要和云端平台对接json协议,由于服务端规定了,需要采用sm2 sm3 sm4用来加密。在嵌入式方面只能用北京大学的GmSSL了。 下载GmSSL 在https://github.com/guanzhi/GmSSL下载库 也可以通过git命令下载&#x…...
【mod分享】极品飞车10高清模组,,全新道路,全新建筑,高清植被,全新的道路围栏,全新的天空,画质直逼极品飞车20。支持光追
各位好,今天小编给大家带来一款新的高清重置魔改MOD,本次高清重置的游戏叫《极品飞车10卡本峡谷》。 《极品飞车10:卡本峡谷》该游戏可选择四个模式:生涯、快速比赛、挑战赛、多人连线游戏模式(已不可用)&…...
做JAVA基础编程题什么网站好/日本免费服务器ip地址
Name That Tune 刚开始我用前缀积优化dp, 精度炸炸的。 我们可以用f[ i ][ j ] 来推出f[ i ][ j 1 ], 记得加加减减仔细一些。。。 #include<bits/stdc.h> #define LL long long #define fi first #define se second #define mk make_pair #defin…...
江门网站优化经验/东莞网站建设最牛
1、安装 一、安装更新Nuget 打开VS菜单“工具”->"扩展与更新"安装更新nuget 二、修改Nuget镜像 打开VS“工具”->“选项”菜单找到“NuGet包管理器”添加https://nuget.cnblogs.com/v3/index.jsonhttp://api.nuget.org/v3/index.jsonhttps://www.nuget.org/ap…...
织梦开发网站/在百度上怎么打广告
1.从今天开始 就详细介绍各个设计模式了。 设计模式总共可以分为三大类: 1.创建型设计模式 :简单理解为(对象怎么来) 2.结构型设计模式:简单理解为 (对象和谁有关系) 3.行为型设计模式&#x…...
网站建设 南宁/网络推广100种方式
20172303 2017-2018-2 《程序设计与数据结构》第9周学习总结 教材学习内容总结 第十一章 异常 1.异常 异常处理 异常处理的常用方法有三种: 根本不处理当异常发生时处理异常在程序的某个位置集中处理异常处理异常的主要方法是捕获异常异常捕获——try-catch语句 格式…...
商城网站建设用乐云seo系统/什么是竞价
众所周知SSD的读写速度远比hdd磁盘要快,理解ssd的工作原理使我们开发处高效储存方案。 linux 相关指令 fstrim --fstab --verbose ## 回收(discard)文件系统上对应磁盘未使用的块 blkdiscard /dev/nvme1n1 ## 回收并擦除(discard)整个SSD块设备 wipefs -a /dev/n…...
商场建设相关网站/福州整站优化
一、非线性分类问题 1、什么是非线性分类问题?非线性分类问题是指通过利用非线性模型才能很好地进行分类的问题。感知机、之前介绍的两种支持向量机模型都是通过一个超平面将数据分成正负两类。但是有些情况并非一条直接或者一个平面就能把数据切分,可能…...