首頁  >  文章  >  系統教程  >  輕鬆掌握Linux儲存解析與分區技巧

輕鬆掌握Linux儲存解析與分區技巧

WBOY
WBOY轉載
2024-02-12 15:54:11515瀏覽

在使用Linux作業系統流程中,我們經常需要對儲存設備進行管理與設定。其中,儲存設備的解析和分區是常見的管理任務之一。了解如何進行儲存解析和分區,可以幫助我們更好地利用儲存資源並提高系統的效能。本文將介紹Linux系統中儲存設備解析與分區的相關知識。

在Linux系統中使用C/C 進行多執行緒程式設計時,我們遇到最多的就是對同一變數的多執行緒讀寫問題,大多情況下遇到這類問題都是透過鎖定機制來處理,但這對程式的效能帶來了很大的影響,當然對於那些系統原生支援原子操作的資料型態來說,我們可以使用原子操作來處理,這能對程式的效能會得到一定的提升。那麼對於那些系統不支援原子操作的自訂資料類型,在不使用鎖的情況下如何做到執行緒安全呢?本文將從線程局部儲存方面,簡單講解處理這一類線程安全問題的方法。

一、資料型別

#在C/C 程式中常存在全域變數、函數內定義的靜態變數、局部變量,對於局部變數來說,其不存在線程安全問題,因此不在本文討論的範圍之內。全域變數和函數內定義的靜態變量,是同一進程中各個執行緒都可以存取的共享變量,因此它們存在多執行緒讀寫問題。在一個執行緒中修改了變數中的內容,其他執行緒都能感知並且能讀取已更改過的內容,這對資料交換來說是非常快速的,但是由於多執行緒的存在,對於同一個變數可能存在兩個或兩個以上的線程同時修改變數所在的記憶體內容,同時又存在多個執行緒在變數在修改的時去讀取該記憶體值,如果沒有使用對應的同步機制來保護該記憶體的話,那麼所讀取到的資料將是不可預測的,甚至可能導致程式崩潰。
如果需要在一個線程內部的各個函數呼叫都能存取、但其它線程不能存取的變量,這就需要新的機制來實現,我們稱之為Static memory local to a thread (線程局部靜態變數),同時也可稱為線程特有資料(TSD: Thread-Specific Data)或線程局部儲存(TLS: Thread-Local Storage)。這類型的數據,在程式中每個執行緒都會分別維護一份變數的副本(copy),並且長期存在於該執行緒中,對此類變數的操作不會影響其他執行緒。如下圖:
輕鬆掌握Linux儲存解析與分區技巧

二、一次初始化

#在講解線程特有資料之前,先讓我們來了解一次性初始化。多線程程式有時有這樣的需求:不管創建多少個線程,有些資料的初始化只能發生一次。列如:在C 程式中某個類別在整個行程的生命週期內只能存在一個實例對象,在多執行緒的情況下,為了能讓該對象能夠安全的初始化,一次性初始化機制就顯得尤為重要了。 ——在設計模式中這種實作常被稱之為單例模式(Singleton)。 Linux中提供瞭如下函數來實現一次性初始化:

#include 

// Returns 0 on success, or a positive error number on error

int pthread_once (pthread_once_t *once_control, void (*init) (void));

利用参数once_control的状态,函数pthread_once()可以确保无论有多少个线程调用多少次该函数,也只会执行一次由init所指向的由调用者定义的函数。init所指向的函数没有任何参数,形式如下:

void init (void)

{

// some variables initializtion in here

}

另外,參數once_control必須是pthread_once_t類型變數的指針,指向初始化為PTHRAD_ONCE_INIT的靜態變數。在C 0x以後提供了類似功能的函數std::call_once (),用法與該函數類似。

三、執行緒局部資料API

在Linux中提供瞭如下函數來對線程局部資料進行操作

#include 

// Returns 0 on success, or a positive error number on error

int pthread_key_create (pthread_key_t *key, void (*destructor)(void *));

// Returns 0 on success, or a positive error number on error

int pthread_key_delete (pthread_key_t key);

// Returns 0 on success, or a positive error number on error

int pthread_setspecific (pthread_key_t key, const void *value);

// Returns pointer, or NULL if no thread-specific data is associated with key

void *pthread_getspecific (pthread_key_t key);

函數pthread_key_create()為執行緒局部資料建立一個新鍵,並透過key指向新建立的鍵緩衝區。因為所有執行緒都可以使用傳回的新鍵,所以參數key可以是一個全域變數(在C 多執行緒程式設計中一般不使用全域變量,而是使用單獨的類別對執行緒局部資料進行封裝,每個變數使用一個獨立的pthread_key_t)。 destructor所指向的是自訂的函數,其格式如下:

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,其格式大概如下:
輕鬆掌握Linux儲存解析與分區技巧
数组的每个元素都是一个包含两个字段的结构,第一个字段标记该数组元素是否在用,第二个字段用于存放针对此键、线程局部存储变的解构函数的一个副本,即destructor函数。
\2. 在常见的存储pthread_setspecific()函数参数value的实现中,大多数都类似于下图的实现。图中假设pthread_keys[1]分配给func1()函数,pthread API为每个函数维护指向线程局部存储数据块的一个指针数组,其中每个数组元素都与图线程局部数据键的实现(上图)中的全局pthread_keys中元素一一对应。
輕鬆掌握Linux儲存解析與分區技巧

五、总结

使用全局变量或者静态变量是导致多线程编程中非线程安全的常见原因。在多线程程序中,保障非线程安全的常用手段之一是使用互斥锁来做保护,这种方法带来了并发性能下降,同时也只能有一个线程对数据进行读写。如果程序中能避免使用全局变量或静态变量,那么这些程序就是线程安全的,性能也可以得到很大的提升。如果有些数据只能有一个线程可以访问,那么这一类数据就可以使用线程局部存储机制来处理,虽然使用这种机制会给程序执行效率上带来一定的影响,但对于使用锁机制来说,这些性能影响将可以忽略。更高性能的线程局部存储机制就是使用__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中文網其他相關文章!

陳述:
本文轉載於:lxlinux.net。如有侵權,請聯絡admin@php.cn刪除