Linux 운영체제를 사용하는 과정에서 저장장치를 관리하고 구성해야 하는 경우가 많습니다. 그 중 저장 장치의 해상도와 파티셔닝은 일반적인 관리 작업 중 하나입니다. 스토리지 구문 분석 및 파티셔닝을 수행하는 방법을 이해하면 스토리지 리소스를 더 잘 활용하고 시스템 성능을 향상시키는 데 도움이 될 수 있습니다. 이 기사에서는 Linux 시스템의 저장 장치 구문 분석 및 파티셔닝에 대한 관련 지식을 소개합니다.
Linux 시스템에서 멀티스레드 프로그래밍을 위해 C/C++를 사용할 때 우리가 직면하는 가장 일반적인 문제는 동일한 변수의 멀티스레드 읽기 및 쓰기입니다. 대부분의 경우 이러한 문제는 잠금 메커니즘을 통해 처리됩니다. 물론 시스템이 기본적으로 원자 연산을 지원하는 데이터 유형의 경우 원자 연산을 사용하여 이를 처리할 수 있으며 이는 프로그램 성능을 어느 정도 향상시킬 수 있습니다. 그렇다면 시스템이 원자적 연산을 지원하지 않는 사용자 정의 데이터 유형의 경우 잠금을 사용하지 않고 스레드 안전성을 어떻게 달성할 수 있습니까? 이 문서에서는 스레드 로컬 저장소 측면에서 이러한 유형의 스레드 안전 문제를 처리하는 방법을 간략하게 설명합니다.
1. 데이터 유형
C/C++ 프로그램에는 전역 변수, 함수 내에 정의된 정적 변수, 지역 변수가 있는 경우가 많습니다. 지역 변수의 경우 스레드 안전성 문제가 없으므로 이 기사의 범위에 포함되지 않습니다. 함수 내에 정의된 전역 변수와 정적 변수는 동일한 프로세스의 모든 스레드에서 접근할 수 있는 공유 변수이므로 멀티 스레드 읽기 및 쓰기 문제가 있습니다. 하나의 스레드에서 변수의 내용이 수정되면 다른 스레드가 변경된 내용을 인식하고 읽을 수 있습니다. 이는 데이터 교환에 매우 빠릅니다. 그러나 멀티 스레드가 존재하기 때문에 동일한 변수에 대해 다른 내용이 있을 수 있습니다. 두 개 이상의 스레드가 변수의 메모리 내용을 동시에 수정하고, 변수가 수정될 때 메모리 값을 읽는 여러 스레드가 메모리를 보호하기 위해 사용되지 않으면 모든 데이터가 읽혀집니다. 예측할 수 없으며 프로그램이 충돌할 수도 있습니다.
스레드 내의 각 함수 호출에서는 액세스할 수 있지만 다른 스레드에서는 액세스할 수 없는 변수가 필요한 경우 이를 구현하기 위한 새로운 메커니즘이 필요합니다. 이를 스레드에 로컬인 정적 메모리(스레드 로컬 정적 변수)라고 합니다. 또한 스레드 특정 데이터(TSD: Thread-Specific Data) 또는 스레드 로컬 저장소(TLS: Thread-Local Storage)라고도 합니다. 이러한 유형의 데이터의 경우 프로그램의 각 스레드는 변수의 복사본을 유지하며 해당 스레드에 오랫동안 존재하게 됩니다. 이러한 변수에 대한 작업은 다른 스레드에 영향을 주지 않습니다. 아래와 같이:
2. 일회성 초기화
스레드별 데이터를 설명하기 전에 먼저 일회성 초기화에 대해 알아보겠습니다. 다중 스레드 프로그램에는 때때로 다음과 같은 요구 사항이 있습니다. 생성된 스레드 수에 관계없이 일부 데이터의 초기화는 한 번만 발생할 수 있습니다. 예를 들어, C++ 프로그램에서는 프로세스의 수명 주기 동안 특정 클래스의 인스턴스 개체가 하나만 존재할 수 있습니다. 멀티스레딩의 경우 개체를 안전하게 초기화하려면 일회성 초기화를 수행해야 합니다. 메커니즘이 특히 중요합니다. ——디자인 패턴에서는 이러한 구현을 흔히 싱글턴 패턴(Singleton)이라고 합니다. Linux는 일회성 초기화를 달성하기 위해 다음 기능을 제공합니다.
으아악또한, 매개변수 Once_control은 PTHRAD_ONCE_INIT로 초기화된 정적 변수를 가리키는 pthread_once_t 유형 변수에 대한 포인터여야 합니다. C++0x 이후에는 비슷한 기능을 가진 std::call_once() 함수가 제공되는데, 사용법은 이 함수와 비슷하다.
3. 스레드 로컬 데이터 API
리눅스에서는 스레드 로컬 데이터를 연산하기 위해 다음과 같은 함수를 제공합니다
으아악pthread_key_create() 함수는 스레드 로컬 데이터에 대한 새 키를 생성하고 키를 통해 새로 생성된 키 버퍼를 가리킵니다. 모든 스레드가 반환된 새 키를 사용할 수 있으므로 매개변수 키는 전역 변수가 될 수 있습니다(전역 변수는 일반적으로 C++ 다중 스레드 프로그래밍에서 사용되지 않지만 스레드 로컬 데이터를 캡슐화하는 데 별도의 클래스가 사용되며 각 변수는 독립적인 pthread_key_t). 소멸자는 다음 형식의 사용자 정의 함수를 가리킵니다.
void Dest (void *value) { // Release storage pointed to by 'value' }
只要线程终止时与key关联的值不为NULL,则destructor所指的函数将会自动被调用。如果一个线程中有多个线程局部存储变量,那么对各个变量所对应的destructor函数的调用顺序是不确定的,因此,每个变量的destructor函数的设计应该相互独立。
函数pthread_key_delete()并不检查当前是否有线程正在使用该线程局部数据变量,也不会调用清理函数destructor,而只是将其释放以供下一次调用pthread_key_create()使用。在Linux线程中,它还会将与之相关的线程数据项设置为NULL。
由于系统对每个进程中pthread_key_t类型的个数是有限制的,所以进程中并不能创建无限个的pthread_key_t变量。Linux中可以通过PTHREAD_KEY_MAX(定义于limits.h文件中)或者系统调用sysconf(_SC_THREAD_KEYS_MAX)来确定当前系统最多支持多少个键。Linux中默认是1024个键,这对于大多数程序来说已经足够了。如果一个线程中有多个线程局部存储变量,通常可以将这些变量封装到一个数据结构中,然后使封装后的数据结构与一个线程局部变量相关联,这样就能减少对键值的使用。
函数pthread_setspecific()用于将value的副本存储于一数据结构中,并将其与调用线程以及key相关联。参数value通常指向由调用者分配的一块内存,当线程终止时,会将该指针作为参数传递给与key相关联的destructor函数。当线程被创建时,会将所有的线程局部存储变量初始化为NULL,因此第一次使用此类变量前必须先调用pthread_getspecific()函数来确认是否已经于对应的key相关联,如果没有,那么pthread_getspecific()会分配一块内存并通过pthread_setspecific()函数保存指向该内存块的指针。
参数value的值也可以不是一个指向调用者分配的内存区域,而是任何可以强制转换为void的变量值,在这种情况下,先前的pthread_key_create()函数应将参数
destructor设置为NULL
函数pthread_getspecific()正好与pthread_setspecific()相反,其是将pthread_setspecific()设置的value取出。在使用取出的值前最好是将void转换成原始数据类型的指针。
四、深入理解线程局部存储机制
\1. 深入理解线程局部存储的实现有助于对其API的使用。在典型的实现中包含以下数组:
pthread_key_create()返回的pthread_key_t类型值只是对全局数组的索引,该全局数组标记为pthread_keys,其格式大概如下:
数组的每个元素都是一个包含两个字段的结构,第一个字段标记该数组元素是否在用,第二个字段用于存放针对此键、线程局部存储变的解构函数的一个副本,即destructor函数。
\2. 在常见的存储pthread_setspecific()函数参数value的实现中,大多数都类似于下图的实现。图中假设pthread_keys[1]分配给func1()函数,pthread API为每个函数维护指向线程局部存储数据块的一个指针数组,其中每个数组元素都与图线程局部数据键的实现(上图)中的全局pthread_keys中元素一一对应。
五、总结
使用全局变量或者静态变量是导致多线程编程中非线程安全的常见原因。在多线程程序中,保障非线程安全的常用手段之一是使用互斥锁来做保护,这种方法带来了并发性能下降,同时也只能有一个线程对数据进行读写。如果程序中能避免使用全局变量或静态变量,那么这些程序就是线程安全的,性能也可以得到很大的提升。如果有些数据只能有一个线程可以访问,那么这一类数据就可以使用线程局部存储机制来处理,虽然使用这种机制会给程序执行效率上带来一定的影响,但对于使用锁机制来说,这些性能影响将可以忽略。更高性能的线程局部存储机制就是使用__thread,这个以后再讨论。
需要C/C++ Linux服务器开发学习资料私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
本文介绍了Linux系统中存储设备解析和分区的相关知识,包括使用fdisk命令、使用parted命令、使用mkfs命令等。了解这些知识,可以帮助我们更好地管理和配置存储设备,优化系统性能。希望读者能够根据实际需求选择适合自己的方法,并加以应用。
위 내용은 Linux 스토리지 구문 분석 및 파티셔닝 기술을 쉽게 익히세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!