前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >c/c++问题集五

c/c++问题集五

原创
作者头像
_咯噔_
发布2022-04-28 14:12:09
1.1K0
发布2022-04-28 14:12:09
举报
文章被收录于专栏:CS学习笔记CS学习笔记

c++的锁

互斥锁、条件锁、自旋锁、读写锁

互斥锁

C++11开始引入了多线程库<thread>,其中也包含了互斥锁的API:std::mutex

头文件:< mutex >

类型: std::mutex

用法:在C++中,通过构造std::mutex的实例创建互斥元,调用成员函数lock()来锁定它,调用unlock()来解锁,不过一般不推荐这种做法,标准C++库提供了std::lock_guard类模板,实现了互斥元的RAII惯用语法。std::mutex和std::lock _ guard。都声明在< mutex >头文件中。Class lock_guard是在声明时,自动上锁,在离开作用域之后自动析构解锁。

条件锁(条件变量)

头文件:< condition_variable >

类型:std::condition_variable(只和std::mutex一起工作) 和 std::condition_variable_any(符合类似互斥元的最低标准的任何东西一起工作)。

最为常见的就是在线程池中,初始情况下因为没有任务使得任务队列为空,此时线程池中的线程因为“任务队列为空”这个条件处于阻塞状态。一旦有任务进来,就会以信号量的方式唤醒该线程来处理这个任务。

自旋锁

从“自旋锁”的名字也可以看出来,如果一个线程想要获取一个被使用的自旋锁,那么它会一直占用CPU请求这个自旋锁使得CPU不能去做其他的事情,直到获取这个锁为止,这就是“自旋”的含义。

自旋锁,没有获取到锁的线程会一直循环等待判断资源是否已经释放锁,不用将线程阻塞起来;互斥锁,把未获取到锁的线程阻塞起来,等待重新调度请求。

获取锁的线程一直处于活跃状态,但并没有执行任何有效的任务,使用自旋锁会造成busy-waiting。互斥锁是sleep-waiting

特点

  1. 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
  2. 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁时需要从内核态恢复,导致线程在用户态与内核态之间来回切换,严重影响锁的性能。

适合场景:

自旋锁的原理比较简单,如果持有锁的线程能在短时间内释放锁资源,那么等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞状态,只需要等一等(自旋),等到持有锁的线程释放锁后即可获取,避免用户进程和内核切换的消耗。

自旋锁的类型:spinlock_t

相关函数:

spin_lock_init(spinlock_t *x); //初始化

spin_lock(x); //只有在获得锁的情况下才返回,否则一直“自旋”

spin_trylock(x); //如立即获得锁则返回真,否则立即返回假

spin_unlock(x); //释放锁

spin_is_locked(x); //该宏用于判断自旋锁x是否已经被某执行单元保持(即被锁),如果是,返回真,否则返回假。

代码语言:javascript
复制
#include <pthread.h>
 
int pthread_spin_destroy(pthread_spinlock_t *lock);
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
 
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);

读写锁

对于多读少写的场景可以用读写锁(也叫共享独占锁),来缓解。

读写锁的类型:pthread_rwlock_t

代码语言:javascript
复制
// 声明一个读写锁
pthread_rwlock_t rwlock;
...
// 在读之前加读锁
pthread_rwlock_rdlock(&rwlock);
 
... 共享资源的读操作
 
// 读完释放锁
pthread_rwlock_unlock(&rwlock);
 
// 在写之前加写锁
pthread_rwlock_wrlock(&rwlock); 
 
... 共享资源的写操作
 
// 写完释放锁
pthread_rwlock_unlock(&rwlock);
 
// 销毁读写锁
pthread_rwlock_destroy(&rwlock);

C++11中有互斥量、条件变量但是并没有引入读写锁。而在C++17中出现了一种新锁:std::shared_mutex。用它可以模拟实现出读写锁

CAS(Compare & Set/Compare & Swap)

CAS是解决多线程并行情况下使用锁造成性能损耗的一种机制。

锁机制存在的问题

  • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
  • 一个线程持有锁会导致其它所有需要此锁的线程挂起。
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。

https://zhuanlan.zhihu.com/p/400817892

  • CAS操作包含三个操作数——内存位置(V)、预期原值(A)、新值(B)。
  • 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。
  • 否则,处理器不做任何操作。
  • 无论哪种情况,它都会在CAS指令之前返回该位置的值。
  • CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

c++内存分配

C++内存分配的方式有三种:分别是从静态存储区分配,从栈上分配内存和从堆上分配内存。

从静态存储区分配内存

从静态存储区域分配的内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。静态分配的区域的生命期是整个软件运行期,就是说从软件运行开始到软件终止退出。只有软件终止运行后,这块内存才会被系统回收。

从栈上分配内存

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但 是分配的内存容量有限。在栈中分配的空间的生命期与这个变量所在的函数和类相关。如果是函数中定义的局部变量,那么它的生命期就是函数被调用时,如果函数运行结束,那么这块内存就会被回收。如果是类中的成员变量,则它的生命期与类实例的生命期相同。

理解:系统自动分配,如声明int a;系统自动在栈空间中为a开辟空间。

从堆上分配内存

亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存 期由我们决定,使用非常灵活,但问题也最多。在堆上分配的内存,生命期是从调用new或者malloc开始,到调用delete或者free结束。如果不 掉用delete或者free。则这块空间必须到软件运行结束后才能被系统回收。

理解:程序员申请,并指明大小 c中的malloc,如charp=(char)malloc(10); C++中的new运算符:如int*p2=new int(10);

补充说明

C++内存布局,也就是一个由c/C++编译的程序占用的内存分为以下几个部分: 1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量值等,其操作方法类似数据结构中的栈。 2、堆区(heap):一般由程序员分配释放,与数据结构中的堆毫无关系,分配方式类似于链表。 3、全局/静态存储区(static):全局变量和静态变量的存储是放在一起的,在程序编译时分配。 4、常量存储区:存放常量字符串。 5、程序代码区:存放函数体(类的成员函数、全局函数)的二进制代码

C++应用程序内存结构

.bss BSS段(bss segment):通常是指用来存放程序中**未初始化**的全局变量的一块内存区域。BSS段属于静态内存分配

.RW data数据段(data segment):通常是指用来存放程序中**已初始化**的全局变量的一块内存区域。数据段属于静态内存分配

.RO data只读数据段:只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。

.text代码段(code segment/text segment):通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行之前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。程序段为程序代码在内存中的映射,一个程序可以在内存中有多个副本。

extern关键字的作用

extern置于变量或函数前,用于标示变量或函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。它只要有两个作用:

  1. 当它与“C”一起连用的时候,如:extern “C” void fun(int a,int b);则告诉编译器在编译fun这个函数时候按着C的规矩去翻译,而不是C++的(这与C++的重载有关,C++语言支持函数重载,C语言不支持函数重载,函数被C++编译器编译后在库中的名字与C语言的不同)
  2. 当extern不与“C”在一起修饰变量或函数时,extern int g_Int,他的作用是声明变量或者函数为外部变量。 如:extern int g_Int;利用关键字extern,可以在一个文件中引用另一个文件中定义的变量或者函数,表明该变量在别的地方已经定义过了,在这里要使用那个变量.

注意:

  1. 注意只有当一个变量是一个全局变量时,extern变量才会起作用。
  2. extern 关键字实质上是声明,别的地方必须实现定义。
  3. extern关键字只需要指明类型和变量名就行了,不能再重新赋值,初始化需要在原文件所在处进行,如果不进行初始化的话,全局变量会被编译器自动初始化为0。像这种写法是不行的,extern int num=4; 但是在声明之后就可以使用变量名进行修改了

extern 和 static

static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;

其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量后,它也同时被定义了;

extern 和const

const可以与extern连用来声明该常量可以作用于其他编译模块中, 如extern const char g_str[];**然后在原文件中别忘了定义: const char g_str[] = “123456”;

内存对齐的原则以及作用?

1).数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节, 则要从4的整数倍地址开始存储),基本类型不包括struct/class/uinon。

2).结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。

3).收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的"最宽基本类型成员"的整数倍.不足的要补齐.(基本类型不包括struct/class/uinon)。

4).sizeof(union),以结构里面size最大元素为union的size,因为在某一时刻,union只有一个成员真正存储于该地址。

内存对齐的主要作用是:

1、  平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、  性能原因:经过内存对齐后,CPU的内存访问速度大大提升。CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度) 本人把它翻译为“内存读取粒度”,举例int型数据的跨块存储

c++结构体和类的区别

struct能包含成员函数吗? 能! struct能继承吗? 能!! struct能实现多态吗? 能!!!

既然这些它都能实现,那它和class还能有什么区别?

最本质的一个区别就是默认的访问控制: 

默认的继承访问权限

struct是public的,class是private的。

当然,到底默认是public继承还是private继承取决于子类而不是基类

我的意思是,struct可以继承class,同样class也可以继承struct,那么默认的继承访问权限是看子类到底是用的struct还是class。如下:

struct A{};class B : A{}; //private继承 struct C : B{}; //public继承

struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的

c++设计模式

单例模式

1.什么是单例模式?

简单来讲,就是在软件系统中,一个类只允许有一个实例,即只能生成一个对象。怎么实现:该类提供了一个静态的公有函数用于创建或者获取它本身的静态私有对象;类定义中含有一个该类的静态私有对象单例模式的类只提供私有的构造函数,防止多个实例创建。单例模式又分为懒汉模式和饿汉模式两种。

单例大约有两种实现方法:懒汉与饿汉

懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化,

饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。

(1)饿汉

饿汉单例,即在最开始的时候,静态对象就已经创建完成; 设计方法是类中包含一个静态成员指针,该指针指向该类的一个对象,提供一个公有的静态成员方法,返回该对象指针;为了使得对象唯一,还需要将构造函数设为私有,代码如下:

代码语言:javascript
复制
// version 1.3
class Singleton
{
private:
	static Singleton instance;
private:
	Singleton();
	~Singleton();
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);
public:
	static Singleton& getInstance() {
		return instance;
	}
}

// initialize defaultly
Singleton Singleton::instance;

单例的饿汉实现是线程安全的,因为对象在使用前就已经创建出来了

(2)懒汉

所谓懒汉模式,就是尽可能晚的创建这个对象的实例,即在单例类第一次被引用时将自己初始化;其实C++里很多地方都是类似这样的思想,比如晚绑定,写时拷贝技术等,就是尽量使资源的利用最大化,不要让空闲的人还占着有限的资源。

代码语言:javascript
复制
class Sigletion2
{
	Sigletion2()
	{
		cout << "Sigletion2()" <<endl;
	}
 
	static Sigletion2* intance2;
 
public:
 
	static Sigletion2* GetSigletion2()
	{
		if (intance2 == NULL)
		{
			intance2 = new Sigletion2();
			cout << "it is once" <<endl;
		}
		else
		{
			cout << "it is not once" <<endl;
		}
		return intance2;
 
	}
 
};
 
Sigletion2* Sigletion2:: intance2 = NULL;  //先初始化为空,等真正用上这个单例的时候再创建这个例。

但是以上代码存在new出来的对象内存泄露的和多线程竞争问题,当两个线程同时进入if (singleton == null)同时创建实例,导致单例模式失效的问题。

(3)懒汉的线程安全问题

加锁,使得线程同步;

代码语言:javascript
复制
class singleton
{
private:
	singleton()
	{
		pthread_mutex_init(&mutex);
	}
 
	static singleton* p;
	static pthread_mutex_t mutex;
public:
	static singleton* initance()
	{
		if (p == NULL)   //p != NULL,说明对象已经创建出来了,直接返回对象的指针,没必要在加锁解锁浪费时间。
		{
			pthread_mutex_lock(&mutex);
			if (p == NULL)
			{
				p = new singleton();
			}
			pthread_mutex_unlock(&mutex);
		}
		return p;
	}
};
 
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;

(4)懒汉模式 - 现代c++11-优雅的多线程版本

双重检测模式和私有嵌套类Delete实现起来代码量略长,c++11标准下,《Effective C++》提出了一种更优雅简易的多线程单例模式实现,使用函数内的 local static ,即static静态局部变量的初始化,编译器会自动加锁和解锁这样,只有当第一次访问getInstance()方法时static静态局部变量才创建实例。

代码语言:javascript
复制
class Singleton{
private:
    Singleton(){printf("Singeleton init \n");};
    ~Singleton(){printf("delete Singeleton \n");};
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) =delete;
public:
    static Singleton* GetInstance(){
        static Singleton instance;  //函数内的静态局部变量,第一次访问才初始化,程序结束,自动释放。
        return &instance;
    }
};

工厂模式

工厂模式,指的是封装对象的创建过程,并将创建过程和操作过程分离(解耦),用户(创建者)无需关心具体过程(最少知识原则),就像一个工厂生产产品一样,以便批量管理对象的创建,提高程序的可以维护性和扩展性。

  • 简单工厂模式,由创建对象类根据传入的类型参数确定对象种类实例。简单工厂模式是工厂模式中最简单的模式,但该模式并未能体现出工厂模式的精髓。

//由一个工厂生产A,B,C

代码语言:javascript
复制
#include <iostream> 
#include <stdlib.h> 

using namespace std;

typedef enum ProductType
{
	TypeA,
	TypeB,
	TypeC
}ProductType_t;

/* 产品抽象基类 */
class Product
{
public:
	virtual void printf() = 0;
};
class ProductA : public Product
{
public:
	void printf()
	{
		cout<<"Create productA"<<endl;
	}
};
class ProductB : public Product
{
public:
	void printf()
	{
		cout<<"Create productB"<<endl;
	}

};
class ProductC : public Product
{
public:
	void printf()
	{
		cout<<"Create productC"<<endl;
	}

};

/* 工厂类 */
class Factory
{
public:
	Product* CreateProduct(ProductType_t type);
};

Product* Factory::CreateProduct(ProductType_t type)
{
	Product *a = NULL;
	
	switch (type)
	{
		case TypeA:
			a = new ProductA();
		break;
		case TypeB:
			a = new ProductB();
		break;
		case TypeC:
			a = new ProductC();
		break;
		default:
		break;
	}
	return a;
}

int main(int argc, char **argv)
{
	Factory productCreator;
	
	Product *productA;
	Product *productB;
	Product *productC; 

	productA = productCreator.CreateProduct(TypeA);
	productB = productCreator.CreateProduct(TypeB);
	productC = productCreator.CreateProduct(TypeC);
	if(productA != NULL)
	{
		productA->printf();
		delete productA;
		productA=NULL;
	}
	if(productB != NULL)
	{
		productB->printf();
		delete productB;
		productB=NULL;
	}
	if(productC != NULL)
	{
		productC->printf();
		delete productC;
		productC=NULL;
	}
	return 0;
}

工厂方法

  • 工厂方法模式,声明一个创建对象的抽象方法基类,子类继承基类,由子类创建具体对象类实例。与简单工厂模式不同,工厂方法模式的对象实例化过程由子类实现。

一个基类工厂,三个子工厂分别生产A,B,C

代码语言:javascript
复制

#include <iostream> 
#include <stdlib.h> 

using namespace std;


/* 产品抽象基类 */
class Product
{
public:
	virtual void printf() = 0;
};
class ProductA : public Product
{
public:
	void printf()
	{
		cout<<"Create productA"<<endl;
	}
};
class ProductB : public Product
{
public:
	void printf()
	{
		cout<<"Create productB"<<endl;
	}

};
class ProductC : public Product
{
public:
	void printf()
	{
		cout<<"Create productC"<<endl;
	}

};

/* 工厂类 */
class Factory
{
public:
	virtual Product* CreateProduct()=0;
};

class FactoryA:public Factory
{
public:
	Product *CreateProduct()
	{
		return new ProductA();
	}
};
class FactoryB:public Factory
{
public:
	Product *CreateProduct()
	{
		return new ProductB();
	}
};

class FactoryC:public Factory
{
public:
	Product *CreateProduct()
	{
		return new ProductC();
	}
};


int main(int argc, char **argv)
{
	Factory *factoryA;
	Factory *factoryB;
	Factory *factoryC;
	Product *productA;
	Product *productB;
	Product *productC; 

	factoryA = new FactoryA(); 
	if(factoryA != NULL)
	{
		productA = factoryA->CreateProduct(); 
		if (productA != NULL)
		{
			productA->printf();
			delete productA;
			productA = NULL;
		}
		delete factoryA;
		factoryA = NULL;
	}
	
	factoryB = new FactoryB(); 
	if(factoryB != NULL)
	{
		productB = factoryB->CreateProduct(); 
		if (productB != NULL)
		{
			productB->printf();
			delete productB;
			productB = NULL;
		}
		delete factoryA;
		factoryA = NULL;
	}
	
	factoryC = new FactoryC(); 
	if(factoryC != NULL)
	{
		productC = factoryC->CreateProduct(); 
		if (productC != NULL)
		{
			productC->printf();
			delete productC;
			productC = NULL;
		}
		delete factoryC;
		factoryC = NULL;
	}
	return 0;
}

工厂抽象

  • 抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。简单工厂和工厂方法只能创建同一类对象,抽象工厂可以创建一系列相关的对象。

//A,B,C都有两种型号0,1,两个工厂分别负责生产0型号的a,b,c和1型号的a,b,c

代码语言:javascript
复制

#include <iostream> 
#include <stdlib.h> 

using namespace std;


/* 产品A抽象基类 */
class ProductA
{
public:
	virtual void printf() = 0;
};

/* 产品类A0 */
class ProductA0 : public ProductA
{
public:
	void printf()
	{
		cout<<"Create productA0"<<endl;
	}
};

/* 产品类A1 */
class ProductA1 : public ProductA
{
public:
	void printf()
	{
		cout<<"Create productA1"<<endl;
	}
};

/* 产品B抽象基类 */
class ProductB
{
public:
	virtual void printf() = 0;
};

/* 产品类B0 */
class ProductB0 : public ProductB
{
public:
	void printf()
	{
		cout<<"Create productB0"<<endl;
	}
};

/* 产品类B1 */
class ProductB1 : public ProductB
{
public:
	void printf()
	{
		cout<<"Create productB1"<<endl;
	}
};

/* 工厂类 */
class Factory
{
public:
	virtual ProductA* CreateProductA()=0;
	virtual ProductB* CreateProductB()=0;
};

/* 工厂类0,专门生产0类产品 */
class Factory0:public Factory
{
public:
	ProductA *CreateProductA()
	{
		return new ProductA0();
	}
	ProductB *CreateProductB()
	{
		return new ProductB0();
	}
};

/* 工厂类1,专门生产1类产品 */
class Factory1:public Factory
{
public:
	ProductA *CreateProductA()
	{
		return new ProductA1();
	}
	ProductB *CreateProductB()
	{
		return new ProductB1();
	}
};

int main(int argc, char **argv)
{
	Factory *factory0;
	Factory *factory1;
	ProductA *productA0;
	ProductA *productA1;
	ProductB *productB0; 
	ProductB *productB1;

	factory0 = new Factory0(); 
	if(factory0 != NULL)
	{
		productA0 = factory0->CreateProductA(); 
		if (productA0 != NULL)
		{
			productA0->printf();
			delete productA0;
			productA0 = NULL;
		}

		productB0 = factory0->CreateProductB(); 
		if (productB0 != NULL)
		{
			productB0->printf();
			delete productB0;
			productB0 = NULL;
		}
		delete factory0;
		factory0 = NULL;
	}
	
	factory1 = new Factory1(); 
	if(factory1 != NULL)
	{
		productA1 = factory1->CreateProductA(); 
		if (productA1 != NULL)
		{
			productA1->printf();
			delete productA1;
			productA1 = NULL;
		}

		productB1 = factory1->CreateProductB(); 
		if (productB1 != NULL)
		{
			productB1->printf();
			delete productB1;
			productB1 = NULL;
		}
		delete factory1;
		factory1 = NULL;
	}
	return 0;
}

观察者模式

指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • c++的锁
  • CAS(Compare & Set/Compare & Swap)
  • 锁机制存在的问题
  • c++内存分配
    • 从静态存储区分配内存
      • 从栈上分配内存
        • 从堆上分配内存
        • 补充说明
          • C++应用程序内存结构
            • extern关键字的作用
              • c++结构体和类的区别
                • c++设计模式
                  • 单例模式
                  • 工厂模式
                  • 工厂方法
                  • 工厂抽象
                  • 观察者模式
              相关产品与服务
              云硬盘
              云硬盘(Cloud Block Storage,CBS)为您提供用于 CVM 的持久性数据块级存储服务。云硬盘中的数据自动地在可用区内以多副本冗余方式存储,避免数据的单点故障风险,提供高达99.9999999%的数据可靠性。同时提供多种类型及规格,满足稳定低延迟的存储性能要求。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档