7.9-UC-第九課:執行緒管理
阿新 • • 發佈:2018-11-29
================
第九課 執行緒管理
================
一、基本概念 ------------
1. 執行緒就是程式的執行路線,即程序內部的控制序列, 或者說是程序的子任務。
2. 執行緒,輕量級,不擁有自己獨立的記憶體資源, 共享程序的程式碼區、資料區、堆區(注意沒有棧區)、 環境變數和命令列引數、檔案描述符、訊號處理函式、 當前目錄、使用者ID和組ID等資源。
3. 執行緒擁有自己獨立的棧,因此也有自己獨立的區域性變數。
4. 一個程序可以同時擁有多個執行緒, 即同時被系統排程的多條執行路線, 但至少要有一個主執行緒。
二、基本特點 ------------
1. 執行緒是程序的一個實體, 可作為系統獨立排程和分派的基本單位。
2. 執行緒有不同的狀態,系統提供了多種執行緒控制原語, 如建立執行緒、銷燬執行緒等等。
3. 執行緒不擁有自己的資源,只擁有從屬於程序的全部資源, 所有的資源分配都是面向程序的。
4. 一個程序中可以有多個執行緒併發地執行。 它們可以執行相同的程式碼,也可以執行不同的程式碼。
5. 同一個程序的多個執行緒都在同一個地址空間內活動, 因此相對於程序,執行緒的系統開銷小,任務切換快。
6. 執行緒間的資料交換不需要依賴於類似IPC的特殊通訊機制, 簡單而高效。
7. 每個執行緒擁有自己獨立的執行緒ID、暫存器資訊、函式棧、 錯誤碼和訊號掩碼。
8. 執行緒之間存在優先順序的差異。
三、POSIX執行緒(pthread) ----------------------
1. 早期廠商各自提供私有的執行緒庫版本, 介面和實現的差異非常大,不易於移植。
2. IEEE POSIX 1003.1c (1995)標準, 定義了統一的執行緒程式設計介面, 遵循該標準的執行緒實現被統稱為POSIX執行緒,即pthread。
3. pthread包含一個頭檔案pthread.h, 和一個介面庫libpthread.so。
#include <pthread.h>
...
gcc ... -lpthread
4. 功能
1) 執行緒管理:建立/銷燬執行緒、分離/聯合執行緒、 設定/查詢執行緒屬性。
2) 執行緒同步
A. 互斥量:建立/銷燬互斥量、加鎖/解鎖互斥量、 設定/查詢互斥量屬性。
B. 條件變數:建立/銷燬條件變數、等待/觸發條件變數、 設定/查詢條件變數屬性。
四、執行緒函式 ------------
1. 建立執行緒 ~~~~~~~~~~~
int pthread_create (pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (*start_routine) (void*), void* restrict arg);
thread - 執行緒ID,輸出引數。 pthread_t即unsigned long int。
attr - 執行緒屬性,NULL表示預設屬性。 pthread_attr_t可能是整型也可能是結構, 因實現而異。
start_routine - 執行緒過程函式指標, 引數和返回值的型別都是void*。 啟動執行緒本質上就是呼叫一個函式, 只不過是在一個獨立的執行緒中呼叫的, 函式返回即執行緒結束。
arg - 傳遞給執行緒過程函式的引數。 執行緒過程函式的呼叫者是系統核心, 而非使用者程式碼, 因此需要在建立執行緒時指定引數。
成功返回0,失敗返回錯誤碼。
注意:
1) restrict: C99引入的編譯優化指示符, 提高重複解引用同一個指標的效率。
2) 在pthread.h標頭檔案中宣告的函式, 通常以直接返回錯誤碼的方式表示失敗, 而非以錯誤碼設定errno並返回-1。
3) main函式即主執行緒,main函式返回即主執行緒結束, 主執行緒結束即程序結束, 程序一但結束其所有的執行緒即結束。
4) 應設法保證線上程過程函式執行期間, 其引數所指向的目標持久有效。
建立執行緒。範例:create.c
執行緒併發。範例:concur.c
執行緒引數。範例:arg.c
2. 等待執行緒 ~~~~~~~~~~~
int pthread_join (pthread_t thread, void** retval);
等待thread引數所標識的執行緒結束, 成功返回0,失敗返回錯誤碼。
範例:ret.c
注意從執行緒過程函式中返回值的方法:
1) 執行緒過程函式將所需返回的內容放在一塊記憶體中, 返回該記憶體的地址,保證這塊記憶體在函式返回, 即執行緒結束,以後依然有效;
2) 若retval引數非NULL, 則pthread_join函式將執行緒過程函式所返回的指標, 拷貝到該引數所指向的記憶體中;
3) 若執行緒過程函式所返回的指標指向動態分配的記憶體, 則還需保證在用過該記憶體之後釋放之。
3. 獲取執行緒自身的ID ~~~~~~~~~~~~~~~~~~~
pthread_t pthread_self (void);
成功返回呼叫執行緒的ID,不會失敗。
4. 比較兩個執行緒的ID ~~~~~~~~~~~~~~~~~~~
int pthread_equal (pthread_t t1, pthread_t t2);
若引數t1和t2所標識的執行緒ID相等,則返回非零,否則返回0。
某些實現的pthread_t不是unsigned long int型別, 可能是結構體型別,無法通過“==”判斷其相等性。
範例:equal.c
5. 終止執行緒 ~~~~~~~~~~~
1) 從執行緒過程函式中return。
2) 呼叫pthread_exit函式。
void pthread_exit (void* retval);
retval - 和執行緒過程函式的返回值語義相同。
注意:在任何執行緒中呼叫exit函式都將終止整個程序。
範例:exit.c
6. 執行緒執行軌跡 ~~~~~~~~~~~~~~~
1) 同步方式(非分離狀態): 建立執行緒之後呼叫pthread_join函式等待其終止, 並釋放執行緒資源。
2) 非同步方式(分離狀態): 無需建立者等待,執行緒終止後自行釋放資源。
int pthread_detach (pthread_t thread);
使thread引數所標識的執行緒進入分離(DETACHED)狀態。 處於分離狀態的執行緒終止後自動釋放執行緒資源, 且不能被pthread_join函式等待。
成功返回0,失敗返回錯誤碼。
範例:detach.c
7. 取消執行緒 ~~~~~~~~~~~
1) 向指定執行緒傳送取消請求
int pthread_cancel (pthread_t thread);
成功返回0,失敗返回錯誤碼。
注意:該函式只是向執行緒發出取消請求, 並不等待執行緒終止。
預設情況下,執行緒在收到取消請求以後,並不會立即終止, 而是仍繼續執行,直到其達到某個取消點。在取消點處, 執行緒檢查其自身是否已被取消了,並做出相應動作。
當執行緒呼叫一些特定函式時,取消點會出現。
2) 設定呼叫執行緒的可取消狀態
int pthread_setcancelstate (int state, int* oldstate);
成功返回0,並通過oldstate引數輸出原可取消狀態 (若非NULL),失敗返回錯誤碼。
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消請求(預設)。
PTHREAD_CANCEL_DISABLE - 忽略取消請求。
3) 設定呼叫執行緒的可取消型別
int pthread_setcanceltype (int type, int* oldtype);
成功返回0,並通過oldtype引數輸出原可取消型別 (若非NULL),失敗返回錯誤碼。
type取值:
PTHREAD_CANCEL_DEFERRED - 延遲取消(預設)。
被取消執行緒在接收到取消請求之後並不立即響應, 而是一直等到執行了特定的函式(取消點)之後再響應該請求。
PTHREAD_CANCEL_ASYNCHRONOUS - 非同步取消。
被取消執行緒可以在任意時間取消, 不是非得遇到取消點才能被取消。 但是作業系統並不能保證這一點。
範例:cancel.c
8. 執行緒屬性 ~~~~~~~~~~~
建立執行緒函式 int pthread_create (pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (*start_routine) (void*), void* restrict arg); 的第二個引數即為執行緒屬性,傳空指標表示使用預設屬性。
typedef struct { // 分離狀態 // // PTHREAD_CREATE_DETACHED // - 分離執行緒。 // // PTHREAD_CREATE_JOINABLE(預設) // - 可匯合執行緒。 // int detachstate;
// 競爭範圍 // // PTHREAD_SCOPE_SYSTEM // - 在系統範圍內競爭資源。 // // PTHREAD_SCOPE_PROCESS(Linux不支援) // - 在程序範圍內競爭資源。 // int scope;
// 繼承特性 // // PTHREAD_INHERIT_SCHED(預設) // - 排程屬性自建立者執行緒繼承。 // // PTHREAD_EXPLICIT_SCHED // - 排程屬性由後面兩個成員確定。 // int inheritsched;
// 排程策略 // // SCHED_FIFO // - 先進先出策略。 // // 沒有時間片。 // // 一個FIFO執行緒會持續執行, // 直到阻塞或有高優先順序執行緒就緒。 // // 當FIFO執行緒阻塞時,系統將其移出就緒佇列, // 待其恢復時再加到同優先順序就緒佇列的末尾。 // // 當FIFO執行緒被高優先順序執行緒搶佔時, // 它在就緒佇列中的位置不變。 // 因此一旦高優先順序執行緒終止或阻塞, // 被搶佔的FIFO執行緒將會立即繼續執行。 // // SCHED_RR // - 輪轉策略。 // // 給每個RR執行緒分配一個時間片, // 一但RR執行緒的時間片耗盡, // 系統即將移到就緒佇列的末尾。 // // SCHED_OTHER(預設) // - 普通策略。 // // 靜態優先順序為0。任何就緒的FIFO執行緒或RR執行緒, // 都會搶佔此類執行緒。 // int schedpolicy;
// 排程引數 // // struct sched_param { // int sched_priority; /* 靜態優先順序 */ // }; // struct sched_param schedparam;
// 棧尾警戒區大小(位元組) // // 預設一頁(4096位元組)。 // size_t guardsize;
// 棧地址 // void* stackaddr;
// 棧大小(位元組) // size_t stacksize; } pthread_attr_t;
不要手工讀寫該結構體, 而應呼叫pthread_attr_set/get函式設定/獲取具體屬性項。
1) 設定執行緒屬性
第一步,初始化執行緒屬性結構體
int pthread_attr_init (pthread_attr_t* attr);
第二步,設定具體執行緒屬性項
int pthread_attr_setdetachstate ( pthread_attr_t* attr, int detachstate);
int pthread_attr_setscope ( pthread_attr_t* attr, int scope);
int pthread_attr_setinheritsched ( pthread_attr_t* attr, int inheritsched);
int pthread_attr_setschedpolicy ( pthread_attr_t* attr, int policy);
int pthread_attr_setschedparam ( pthread_attr_t* attr, const struct sched_param* param);
int pthread_attr_setguardsize ( pthread_attr_t* attr, size_t guardsize);
int pthread_attr_setstackaddr ( pthread_attr_t* attr, void* stackaddr);
int pthread_attr_setstacksize ( pthread_attr_t* attr, size_t stacksize);
int pthread_attr_setstack ( pthread_attr_t* attr, void* stackaddr, size_t stacksize);
第三步,以設定好的執行緒屬性結構體為引數建立執行緒
int pthread_create (pthread_t* restrict thread, const pthread_attr_t* testrict attr, void* (*start_routine) (void*), void* restrict arg);
第四步,銷燬執行緒屬性結構體
int pthread_attr_destroy (pthread_attr_t* attr);
2) 獲取執行緒屬性
第一步,獲取執行緒屬性結構體
int pthread_getattr_np (pthread_t thread, pthread_attr_t* attr);
第二步,獲取具體執行緒屬性項
int pthread_attr_getdetachstate ( pthread_attr_t* attr, int* detachstate);
int pthread_attr_getscope ( pthread_attr_t* attr, int* scope);
int pthread_attr_getinheritsched ( pthread_attr_t* attr, int* inheritsched);
int pthread_attr_getschedpolicy ( pthread_attr_t* attr, int* policy);
int pthread_attr_getschedparam ( pthread_attr_t* attr, struct sched_param* param);
int pthread_attr_getguardsize ( pthread_attr_t* attr, size_t* guardsize);
int pthread_attr_getstackaddr ( pthread_attr_t* attr, void** stackaddr);
int pthread_attr_getstacksize ( pthread_attr_t* attr, size_t* stacksize);
int pthread_attr_getstack ( pthread_attr_t* attr, void** stackaddr, size_t* stacksize);
以上所有函式成功返回0,失敗返回錯誤碼。
範例:attr.c
來自為知筆記(Wiz)
一、基本概念 ------------
1. 執行緒就是程式的執行路線,即程序內部的控制序列, 或者說是程序的子任務。
2. 執行緒,輕量級,不擁有自己獨立的記憶體資源, 共享程序的程式碼區、資料區、堆區(注意沒有棧區)、 環境變數和命令列引數、檔案描述符、訊號處理函式、 當前目錄、使用者ID和組ID等資源。
3. 執行緒擁有自己獨立的棧,因此也有自己獨立的區域性變數。
4. 一個程序可以同時擁有多個執行緒, 即同時被系統排程的多條執行路線, 但至少要有一個主執行緒。
二、基本特點 ------------
1. 執行緒是程序的一個實體, 可作為系統獨立排程和分派的基本單位。
2. 執行緒有不同的狀態,系統提供了多種執行緒控制原語, 如建立執行緒、銷燬執行緒等等。
3. 執行緒不擁有自己的資源,只擁有從屬於程序的全部資源, 所有的資源分配都是面向程序的。
4. 一個程序中可以有多個執行緒併發地執行。 它們可以執行相同的程式碼,也可以執行不同的程式碼。
5. 同一個程序的多個執行緒都在同一個地址空間內活動, 因此相對於程序,執行緒的系統開銷小,任務切換快。
6. 執行緒間的資料交換不需要依賴於類似IPC的特殊通訊機制, 簡單而高效。
7. 每個執行緒擁有自己獨立的執行緒ID、暫存器資訊、函式棧、 錯誤碼和訊號掩碼。
8. 執行緒之間存在優先順序的差異。
三、POSIX執行緒(pthread) ----------------------
1. 早期廠商各自提供私有的執行緒庫版本, 介面和實現的差異非常大,不易於移植。
2. IEEE POSIX 1003.1c (1995)標準, 定義了統一的執行緒程式設計介面, 遵循該標準的執行緒實現被統稱為POSIX執行緒,即pthread。
3. pthread包含一個頭檔案pthread.h, 和一個介面庫libpthread.so。
#include <pthread.h>
...
gcc ... -lpthread
4. 功能
1) 執行緒管理:建立/銷燬執行緒、分離/聯合執行緒、 設定/查詢執行緒屬性。
2) 執行緒同步
A. 互斥量:建立/銷燬互斥量、加鎖/解鎖互斥量、 設定/查詢互斥量屬性。
B. 條件變數:建立/銷燬條件變數、等待/觸發條件變數、 設定/查詢條件變數屬性。
四、執行緒函式 ------------
1. 建立執行緒 ~~~~~~~~~~~
int pthread_create (pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (*start_routine) (void*), void* restrict arg);
thread - 執行緒ID,輸出引數。 pthread_t即unsigned long int。
attr - 執行緒屬性,NULL表示預設屬性。 pthread_attr_t可能是整型也可能是結構, 因實現而異。
start_routine - 執行緒過程函式指標, 引數和返回值的型別都是void*。 啟動執行緒本質上就是呼叫一個函式, 只不過是在一個獨立的執行緒中呼叫的, 函式返回即執行緒結束。
arg - 傳遞給執行緒過程函式的引數。 執行緒過程函式的呼叫者是系統核心, 而非使用者程式碼, 因此需要在建立執行緒時指定引數。
成功返回0,失敗返回錯誤碼。
注意:
1) restrict: C99引入的編譯優化指示符, 提高重複解引用同一個指標的效率。
2) 在pthread.h標頭檔案中宣告的函式, 通常以直接返回錯誤碼的方式表示失敗, 而非以錯誤碼設定errno並返回-1。
3) main函式即主執行緒,main函式返回即主執行緒結束, 主執行緒結束即程序結束, 程序一但結束其所有的執行緒即結束。
4) 應設法保證線上程過程函式執行期間, 其引數所指向的目標持久有效。
建立執行緒。範例:create.c
執行緒併發。範例:concur.c
執行緒引數。範例:arg.c
2. 等待執行緒 ~~~~~~~~~~~
int pthread_join (pthread_t thread, void** retval);
等待thread引數所標識的執行緒結束, 成功返回0,失敗返回錯誤碼。
範例:ret.c
注意從執行緒過程函式中返回值的方法:
1) 執行緒過程函式將所需返回的內容放在一塊記憶體中, 返回該記憶體的地址,保證這塊記憶體在函式返回, 即執行緒結束,以後依然有效;
2) 若retval引數非NULL, 則pthread_join函式將執行緒過程函式所返回的指標, 拷貝到該引數所指向的記憶體中;
3) 若執行緒過程函式所返回的指標指向動態分配的記憶體, 則還需保證在用過該記憶體之後釋放之。
3. 獲取執行緒自身的ID ~~~~~~~~~~~~~~~~~~~
pthread_t pthread_self (void);
成功返回呼叫執行緒的ID,不會失敗。
4. 比較兩個執行緒的ID ~~~~~~~~~~~~~~~~~~~
int pthread_equal (pthread_t t1, pthread_t t2);
若引數t1和t2所標識的執行緒ID相等,則返回非零,否則返回0。
某些實現的pthread_t不是unsigned long int型別, 可能是結構體型別,無法通過“==”判斷其相等性。
範例:equal.c
5. 終止執行緒 ~~~~~~~~~~~
1) 從執行緒過程函式中return。
2) 呼叫pthread_exit函式。
void pthread_exit (void* retval);
retval - 和執行緒過程函式的返回值語義相同。
注意:在任何執行緒中呼叫exit函式都將終止整個程序。
範例:exit.c
6. 執行緒執行軌跡 ~~~~~~~~~~~~~~~
1) 同步方式(非分離狀態): 建立執行緒之後呼叫pthread_join函式等待其終止, 並釋放執行緒資源。
2) 非同步方式(分離狀態): 無需建立者等待,執行緒終止後自行釋放資源。
int pthread_detach (pthread_t thread);
使thread引數所標識的執行緒進入分離(DETACHED)狀態。 處於分離狀態的執行緒終止後自動釋放執行緒資源, 且不能被pthread_join函式等待。
成功返回0,失敗返回錯誤碼。
範例:detach.c
7. 取消執行緒 ~~~~~~~~~~~
1) 向指定執行緒傳送取消請求
int pthread_cancel (pthread_t thread);
成功返回0,失敗返回錯誤碼。
注意:該函式只是向執行緒發出取消請求, 並不等待執行緒終止。
預設情況下,執行緒在收到取消請求以後,並不會立即終止, 而是仍繼續執行,直到其達到某個取消點。在取消點處, 執行緒檢查其自身是否已被取消了,並做出相應動作。
當執行緒呼叫一些特定函式時,取消點會出現。
2) 設定呼叫執行緒的可取消狀態
int pthread_setcancelstate (int state, int* oldstate);
成功返回0,並通過oldstate引數輸出原可取消狀態 (若非NULL),失敗返回錯誤碼。
state取值:
PTHREAD_CANCEL_ENABLE - 接受取消請求(預設)。
PTHREAD_CANCEL_DISABLE - 忽略取消請求。
3) 設定呼叫執行緒的可取消型別
int pthread_setcanceltype (int type, int* oldtype);
成功返回0,並通過oldtype引數輸出原可取消型別 (若非NULL),失敗返回錯誤碼。
type取值:
PTHREAD_CANCEL_DEFERRED - 延遲取消(預設)。
被取消執行緒在接收到取消請求之後並不立即響應, 而是一直等到執行了特定的函式(取消點)之後再響應該請求。
PTHREAD_CANCEL_ASYNCHRONOUS - 非同步取消。
被取消執行緒可以在任意時間取消, 不是非得遇到取消點才能被取消。 但是作業系統並不能保證這一點。
範例:cancel.c
8. 執行緒屬性 ~~~~~~~~~~~
建立執行緒函式 int pthread_create (pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (*start_routine) (void*), void* restrict arg); 的第二個引數即為執行緒屬性,傳空指標表示使用預設屬性。
typedef struct { // 分離狀態 // // PTHREAD_CREATE_DETACHED // - 分離執行緒。 // // PTHREAD_CREATE_JOINABLE(預設) // - 可匯合執行緒。 // int detachstate;
// 競爭範圍 // // PTHREAD_SCOPE_SYSTEM // - 在系統範圍內競爭資源。 // // PTHREAD_SCOPE_PROCESS(Linux不支援) // - 在程序範圍內競爭資源。 // int scope;
// 繼承特性 // // PTHREAD_INHERIT_SCHED(預設) // - 排程屬性自建立者執行緒繼承。 // // PTHREAD_EXPLICIT_SCHED // - 排程屬性由後面兩個成員確定。 // int inheritsched;
// 排程策略 // // SCHED_FIFO // - 先進先出策略。 // // 沒有時間片。 // // 一個FIFO執行緒會持續執行, // 直到阻塞或有高優先順序執行緒就緒。 // // 當FIFO執行緒阻塞時,系統將其移出就緒佇列, // 待其恢復時再加到同優先順序就緒佇列的末尾。 // // 當FIFO執行緒被高優先順序執行緒搶佔時, // 它在就緒佇列中的位置不變。 // 因此一旦高優先順序執行緒終止或阻塞, // 被搶佔的FIFO執行緒將會立即繼續執行。 // // SCHED_RR // - 輪轉策略。 // // 給每個RR執行緒分配一個時間片, // 一但RR執行緒的時間片耗盡, // 系統即將移到就緒佇列的末尾。 // // SCHED_OTHER(預設) // - 普通策略。 // // 靜態優先順序為0。任何就緒的FIFO執行緒或RR執行緒, // 都會搶佔此類執行緒。 // int schedpolicy;
// 排程引數 // // struct sched_param { // int sched_priority; /* 靜態優先順序 */ // }; // struct sched_param schedparam;
// 棧尾警戒區大小(位元組) // // 預設一頁(4096位元組)。 // size_t guardsize;
// 棧地址 // void* stackaddr;
// 棧大小(位元組) // size_t stacksize; } pthread_attr_t;
不要手工讀寫該結構體, 而應呼叫pthread_attr_set/get函式設定/獲取具體屬性項。
1) 設定執行緒屬性
第一步,初始化執行緒屬性結構體
int pthread_attr_init (pthread_attr_t* attr);
第二步,設定具體執行緒屬性項
int pthread_attr_setdetachstate ( pthread_attr_t* attr, int detachstate);
int pthread_attr_setscope ( pthread_attr_t* attr, int scope);
int pthread_attr_setinheritsched ( pthread_attr_t* attr, int inheritsched);
int pthread_attr_setschedpolicy ( pthread_attr_t* attr, int policy);
int pthread_attr_setschedparam ( pthread_attr_t* attr, const struct sched_param* param);
int pthread_attr_setguardsize ( pthread_attr_t* attr, size_t guardsize);
int pthread_attr_setstackaddr ( pthread_attr_t* attr, void* stackaddr);
int pthread_attr_setstacksize ( pthread_attr_t* attr, size_t stacksize);
int pthread_attr_setstack ( pthread_attr_t* attr, void* stackaddr, size_t stacksize);
第三步,以設定好的執行緒屬性結構體為引數建立執行緒
int pthread_create (pthread_t* restrict thread, const pthread_attr_t* testrict attr, void* (*start_routine) (void*), void* restrict arg);
第四步,銷燬執行緒屬性結構體
int pthread_attr_destroy (pthread_attr_t* attr);
2) 獲取執行緒屬性
第一步,獲取執行緒屬性結構體
int pthread_getattr_np (pthread_t thread, pthread_attr_t* attr);
第二步,獲取具體執行緒屬性項
int pthread_attr_getdetachstate ( pthread_attr_t* attr, int* detachstate);
int pthread_attr_getscope ( pthread_attr_t* attr, int* scope);
int pthread_attr_getinheritsched ( pthread_attr_t* attr, int* inheritsched);
int pthread_attr_getschedpolicy ( pthread_attr_t* attr, int* policy);
int pthread_attr_getschedparam ( pthread_attr_t* attr, struct sched_param* param);
int pthread_attr_getguardsize ( pthread_attr_t* attr, size_t* guardsize);
int pthread_attr_getstackaddr ( pthread_attr_t* attr, void** stackaddr);
int pthread_attr_getstacksize ( pthread_attr_t* attr, size_t* stacksize);
int pthread_attr_getstack ( pthread_attr_t* attr, void** stackaddr, size_t* stacksize);
以上所有函式成功返回0,失敗返回錯誤碼。
範例:attr.c