uc筆記11---執行緒管理,執行緒函式:建立、等待、獲取、比較、終止、取消, 執行緒屬性
阿新 • • 發佈:2019-02-03
1. 基本概念
1)執行緒就是程式的執行路線,即程序內部的控制序列,或者說是程序的子任務。
2)執行緒,輕量級,不擁有自己獨立的記憶體資源,共享程序的程式碼區、資料區、堆區(注意沒有棧區)、
環境變數和命令列引數、檔案描述符、訊號處理函式、當前目錄、使用者 ID 和組 ID 等資源。
3)執行緒擁有自己獨立的棧,因此也有自己獨立的區域性變數。
4)一個程序可以同時擁有多個執行緒,即同時被系統排程的多條執行路線,但至少要有一個主執行緒。
執行緒是排程的基本單位;程序是資源分配的基本單位;
2. 基本特點
1)執行緒是程序的一個實體,可作為系統獨立排程和分派的基本單位。
2)執行緒有不同的狀態,系統提供了多種執行緒控制原語,如建立執行緒、銷燬執行緒等等。
3)執行緒不擁有自己的資源,只擁有從屬於程序的全部資源,所有的資源分配都是面向程序的。
4)一個程序中可以有多個執行緒併發地執行;它們可以執行相同的程式碼,也可以執行不同的程式碼。
5)同一個程序的多個執行緒都在同一個地址空間內活動,因此相對於程序,執行緒的系統開銷小,任務切換快。
6)執行緒間的資料交換不需要依賴於類似 IPC 的特殊通訊機制,簡單而高效。
7)每個執行緒擁有自己獨立的執行緒 ID、暫存器資訊、函式棧、錯誤碼和訊號掩碼。
8)執行緒之間存在優先順序的差異。
3. POSIX 執行緒 (pthread)
1)早期廠商各自提供私有的執行緒庫版本,介面和實現的差異非常大,不易於移植。
2)IEEE POSIX 1003.1c (1995) 標準,定義了統一的執行緒程式設計介面,
遵循該標準的執行緒實現被統稱為 POSIX 執行緒,即 pthread。
3)pthread 包含一個頭檔案 pthread.h,和一個介面庫 libpthread.so。
#include <pthread.h>
. . .
# gcc ... -lpthread
4)功能
執行緒管理:建立/銷燬執行緒、分離/聯合執行緒、設定/查詢執行緒屬性。
執行緒同步:
A. 互斥量:建立/銷燬互斥量、加鎖/解鎖互斥量、設定/查詢互斥量屬性。
B. 條件變數:建立/銷燬條件變數、等待/觸發條件變數、設定/查詢條件變數屬性。
4. 執行緒函式
建立執行緒
====
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
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
printf ("%lu執行緒:%s\n", pthread_self (), (char*)arg);
return NULL;
}
int main (void) {
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, "我是快樂的子執行緒!");
if (error) {
// 這裡列印錯誤,不能用 perror 或者 \m
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
printf ("%lu執行緒:我是主執行緒,建立了%lu執行緒。\n", pthread_self (), tid);
sleep (1);
return 0;
}
執行緒併發;範例:concur.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
size_t i;
for (i = 0; i < 500; i++) {
printf ("%*d\n", ((size_t)arg + 1) * 4, i + 1);
usleep (50000);
}
return NULL;
}
int main (void) {
pthread_t tids[20];
size_t i;
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_create (&tids[i], NULL, thread_proc, (void*)i);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
}
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_join (tids[i], NULL);
if (error) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
}
return 0;
}
執行緒引數;範例:arg.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
*(double*)arg = PAI * r * r;
return NULL;
}
typedef struct tag_Pyth {
double a;
double b;
double c;
} PYTH, *LPPYTH;
void* thread_pyth (void* arg) {
LPPYTH pyth = (LPPYTH)arg;
pyth -> c = sqrt (pyth -> a * pyth -> a + pyth -> b * pyth -> b);
return NULL;
}
void* thread_aver (void* arg) {
double* d = (double*)arg;
d[2] = (d[0] + d[1]) / 2;
return NULL;
}
void* thread_show (void* arg) {
sleep (1);
printf ("n = %d\n", *(int*)arg);
return NULL;
}
int main (void) {
printf ("r = ");
double rs;
scanf ("%lf", &rs);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &rs);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) { // pthread_join 參見下面
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", rs);
PYTH pyth;
printf ("a = ");
scanf ("%lf", &pyth.a);
printf ("b = ");
scanf ("%lf", &pyth.b);
if ((error = pthread_create (&tid, NULL, thread_pyth, &pyth)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("c = %g\n", pyth.c);
double d[3];
printf ("x = ");
scanf ("%lf", &d[0]);
printf ("y = ");
scanf ("%lf", &d[1]);
if ((error = pthread_create (&tid, NULL, thread_aver, d)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("z = %g\n", d[2]);
int* n = malloc (sizeof (int));
*n = 1234;
if ((error = pthread_create (&tid, NULL, thread_show, n)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
/*
free (n);
*/
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
free (n);
return 0;
}
等待執行緒
====
int pthread_join (pthread_t thread, void** retval);
等待 thread 引數所標識的執行緒結束,成功返回 0,失敗返回錯誤碼。
範例:ret.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
/*
static double s;
s = PAI * r * r;
return &s;
*/
double* s = malloc (sizeof (double));
*s = PAI * r * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
注意從執行緒過程函式中返回值的方法:
1) 執行緒過程函式將所需返回的內容放在一塊記憶體中,
返回該記憶體的地址,保證這塊記憶體在函式返回,即執行緒結束,以後依然有效;
2) 若 retval 引數非 NULL,則 pthread_join 函式將執行緒過程函式所返回的指標,
拷貝到該引數所指向的記憶體中;
3) 若執行緒過程函式所返回的指標指向動態分配的記憶體,
則還需保證在用過該記憶體之後釋放之。
獲取執行緒自身的 ID
=========
pthread_t pthread_self (void);
成功返回呼叫執行緒的 ID,不會失敗。
比較兩個執行緒的 ID
=========
int pthread_equal (pthread_t t1, pthread_t t2);
若引數 t1 和 t2 所標識的執行緒 ID 相等,則返回非零,否則返回 0。
某些實現的 pthread_t 不是 unsigned long int 型別,
可能是結構體型別,無法通過“==”判斷其相等性。
範例:equal.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_t g_main;
void* ismain (void* arg) {
// if (pthread_self () == g_main)
if (pthread_equal (pthread_self (), g_main))
printf ("我是主執行緒!\n");
else
printf ("我不是主執行緒!\n");
return NULL;
}
int main (void) {
g_main = pthread_self ()
ismain (NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, ismain, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
return 0;
}
終止執行緒
====
1) 從執行緒過程函式中 return。
2) 呼叫 pthread_exit 函式。
void pthread_exit (void* retval);
retval - 和執行緒過程函式的返回值語義相同。
注意:在任何執行緒中呼叫 exit 函式都將終止整個程序。
範例:exit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
double* s = malloc (sizeof (double));
// exit (0);
*s = PAI * r * r;
pthread_exit (s); // <==> return s;
*s = 2 * PAI * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
執行緒執行軌跡
======
1) 同步方式 (非分離狀態):
建立執行緒之後呼叫 pthread_join 函式等待其終止,並釋放執行緒資源。
2) 非同步方式 (分離狀態):
無需建立者等待,執行緒終止後自行釋放資源。
int pthread_detach (pthread_t thread);
使 thread 引數所標識的執行緒進入分離 (DETACHED) 狀態。
處於分離狀態的執行緒終止後自動釋放執行緒資源,且不能被 pthread_join 函式等待。
成功返回 0,失敗返回錯誤碼。
範例:detach.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
int i;
for (i = 0; i < 200; i++) {
putchar ('-');
usleep (50000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
// pthread_detach () 寫在 thread_proc () 裡面依然會被 pthread_join () 捕獲,無效果;
if ((error = pthread_detach (tid)) != 0) {
fprintf (stderr, "pthread_detach: %s\n", strerror (error));
return -1;
}
/*
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
*/
int i;
for (i = 0; i < 200; i++) {
putchar ('+');
usleep (100000);
}
printf ("\n");
return 0;
}
取消執行緒
====
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void elapse (void) {
size_t i;
for (i = 0; i < 800000000; ++i);
}
void* thread_proc (void* arg) {
/*
int error = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
if (error) {
fprintf (stderr, "pthread_setcancelstate: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*//*
int error = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (error) {
fprintf (stderr, "pthread_setcanceltype: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*/
for (;;) {
printf ("執行緒:子在川上曰,逝者如斯夫。\n");
elapse ();
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
printf ("按<回車>取消執行緒...\n");
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
getchar ();
if ((error = pthread_cancel (tid)) != 0) {
fprintf (stderr, "pthread_cancel: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
printf ("已傳送取消請求,等待執行緒終止...\n");
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("執行緒已終止。\n");
return 0;
}
執行緒屬性
====
建立執行緒函式
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
int printattrs (pthread_attr_t* attr) {
printf("------- 執行緒屬性 -------\n");
int detachstate;
int error = pthread_attr_getdetachstate (attr, &detachstate);
if (error) {
fprintf (stderr, "pthread_attr_getdetachstate: %s\n", strerror (error));
return -1;
}
printf("分離狀態: %s\n",
(detachstate == PTHREAD_CREATE_DETACHED) ? "分離執行緒" :
(detachstate == PTHREAD_CREATE_JOINABLE) ? "可匯合執行緒" : "未知");
int scope;
if ((error = pthread_attr_getscope (attr, &scope)) != 0) {
fprintf (stderr, "pthread_attr_getscope: %s\n", strerror (error));
return -1;
}
printf ("競爭範圍: %s\n",
(scope == PTHREAD_SCOPE_SYSTEM) ? "系統級競爭" :
(scope == PTHREAD_SCOPE_PROCESS) ? "程序級競爭" : "未知");
int inheritsched;
if ((error = pthread_attr_getinheritsched (attr, &inheritsched)) != 0) {
fprintf (stderr, "pthread_attr_getinheritsched: %s\n", strerror (error));
return -1;
}
printf ("繼承特性: %s\n",
(inheritsched == PTHREAD_INHERIT_SCHED) ? "繼承呼叫屬性" :
(inheritsched == PTHREAD_EXPLICIT_SCHED) ? "顯式呼叫屬性" : "未知");
int schedpolicy;
if ((error = pthread_attr_getschedpolicy(attr, &schedpolicy)) != 0) {
fprintf (stderr, "pthread_attr_getschedpolicy: %s\n", strerror (error));
return -1;
}
printf ("排程策略: %s\n",
(schedpolicy == SCHED_OTHER) ? "普通" :
(schedpolicy == SCHED_FIFO) ? "先進先出" :
(schedpolicy == SCHED_RR) ? "輪轉" : "未知");
struct sched_param schedparam;
if ((error = pthread_attr_getschedparam (attr, &schedparam)) != 0) {
fprintf (stderr, "pthread_attr_getschedparam: %s\n", strerror (error));
return -1;
}
printf ("排程優先順序:%d\n", schedparam.sched_priority);
size_t guardsize;
if ((error = pthread_attr_getguardsize(attr, &guardsize)) != 0) {
fprintf (stderr, "pthread_attr_getguardsize: %s\n", strerror (error));
return -1;
}
printf ("棧尾警戒區:%u位元組\n", guardsize);
/*
void* stackaddr;
if ((error = pthread_attr_getstackaddr (attr, &stackaddr)) != 0) {
fprintf (stderr, "pthread_attr_getstackaddr: %s\n", strerror (error));
return -1;
}
printf ("棧地址: %p\n", stackaddr);
size_t stacksize;
if ((error = pthread_attr_getstacksize (attr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstacksize: %s\n", strerror (error));
return -1;
}
printf ("棧大小: %u位元組\n", stacksize);
*/
void* stackaddr;
size_t stacksize;
if ((error = pthread_attr_getstack (attr, &stackaddr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstack: %s\n", strerror (error));
return -1;
}
printf ("棧地址: %p\n", stackaddr);
printf ("棧大小: %u位元組\n", stacksize);
printf("------------------------\n");
return 0;
}
void* thread_proc (void* arg) {
pthread_attr_t attr;
int error = pthread_getattr_np (pthread_self (), &attr);
if (error) {
fprintf (stderr, "pthread_getattr_np: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
if (printattrs (&attr) < 0)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
return NULL;
}
int main (int argc, char* argv[]) {
int error;
pthread_attr_t attr, *pattr = NULL;
if (argc > 1) {
if (strcmp (argv[1], "-s")) {
fprintf (stderr, "用法:%s [-s]\n", argv[0]);
return -1;
}
if ((error = pthread_attr_init (&attr)) != 0) {
fprintf (stderr, "pthread_attr_init: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setdetachstate (&attr,
PTHREAD_CREATE_DETACHED)) != 0) {
fprintf (stderr, "pthread_attr_setdetachstate: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setinheritsched (&attr,
PTHREAD_EXPLICIT_SCHED)) != 0) {
fprintf (stderr, "pthread_attr_setinheritsched: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setstacksize (&attr, 4096*10)) != 0) {
fprintf (stderr, "pthread_attr_setstack: %s\n", strerror (error));
return -1;
}
pattr = &attr;
}
pthread_t tid;
if ((error = pthread_create (&tid, pattr, thread_proc, NULL)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if (pattr)
if ((error = pthread_attr_destroy (pattr)) != 0) {
fprintf (stderr, "pthread_attr_destroy: %s\n", strerror (error));
return -1;
}
pause ();
return 0;
}
1)執行緒就是程式的執行路線,即程序內部的控制序列,或者說是程序的子任務。
2)執行緒,輕量級,不擁有自己獨立的記憶體資源,共享程序的程式碼區、資料區、堆區(注意沒有棧區)、
環境變數和命令列引數、檔案描述符、訊號處理函式、當前目錄、使用者 ID 和組 ID 等資源。
3)執行緒擁有自己獨立的棧,因此也有自己獨立的區域性變數。
4)一個程序可以同時擁有多個執行緒,即同時被系統排程的多條執行路線,但至少要有一個主執行緒。
執行緒是排程的基本單位;程序是資源分配的基本單位;
2. 基本特點
1)執行緒是程序的一個實體,可作為系統獨立排程和分派的基本單位。
2)執行緒有不同的狀態,系統提供了多種執行緒控制原語,如建立執行緒、銷燬執行緒等等。
3)執行緒不擁有自己的資源,只擁有從屬於程序的全部資源,所有的資源分配都是面向程序的。
4)一個程序中可以有多個執行緒併發地執行;它們可以執行相同的程式碼,也可以執行不同的程式碼。
5)同一個程序的多個執行緒都在同一個地址空間內活動,因此相對於程序,執行緒的系統開銷小,任務切換快。
6)執行緒間的資料交換不需要依賴於類似 IPC 的特殊通訊機制,簡單而高效。
7)每個執行緒擁有自己獨立的執行緒 ID、暫存器資訊、函式棧、錯誤碼和訊號掩碼。
8)執行緒之間存在優先順序的差異。
3. POSIX 執行緒 (pthread)
1)早期廠商各自提供私有的執行緒庫版本,介面和實現的差異非常大,不易於移植。
2)IEEE POSIX 1003.1c (1995) 標準,定義了統一的執行緒程式設計介面,
遵循該標準的執行緒實現被統稱為 POSIX 執行緒,即 pthread。
3)pthread 包含一個頭檔案 pthread.h,和一個介面庫 libpthread.so。
#include <pthread.h>
. . .
# gcc ... -lpthread
4)功能
執行緒管理:建立/銷燬執行緒、分離/聯合執行緒、設定/查詢執行緒屬性。
執行緒同步:
A. 互斥量:建立/銷燬互斥量、加鎖/解鎖互斥量、設定/查詢互斥量屬性。
B. 條件變數:建立/銷燬條件變數、等待/觸發條件變數、設定/查詢條件變數屬性。
4. 執行緒函式
建立執行緒
====
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
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
printf ("%lu執行緒:%s\n", pthread_self (), (char*)arg);
return NULL;
}
int main (void) {
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, "我是快樂的子執行緒!");
if (error) {
// 這裡列印錯誤,不能用 perror 或者 \m
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
printf ("%lu執行緒:我是主執行緒,建立了%lu執行緒。\n", pthread_self (), tid);
sleep (1);
return 0;
}
執行緒併發;範例:concur.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
size_t i;
for (i = 0; i < 500; i++) {
printf ("%*d\n", ((size_t)arg + 1) * 4, i + 1);
usleep (50000);
}
return NULL;
}
int main (void) {
pthread_t tids[20];
size_t i;
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_create (&tids[i], NULL, thread_proc, (void*)i);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
}
for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
int error = pthread_join (tids[i], NULL);
if (error) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
}
return 0;
}
執行緒引數;範例:arg.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
*(double*)arg = PAI * r * r;
return NULL;
}
typedef struct tag_Pyth {
double a;
double b;
double c;
} PYTH, *LPPYTH;
void* thread_pyth (void* arg) {
LPPYTH pyth = (LPPYTH)arg;
pyth -> c = sqrt (pyth -> a * pyth -> a + pyth -> b * pyth -> b);
return NULL;
}
void* thread_aver (void* arg) {
double* d = (double*)arg;
d[2] = (d[0] + d[1]) / 2;
return NULL;
}
void* thread_show (void* arg) {
sleep (1);
printf ("n = %d\n", *(int*)arg);
return NULL;
}
int main (void) {
printf ("r = ");
double rs;
scanf ("%lf", &rs);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &rs);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) { // pthread_join 參見下面
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", rs);
PYTH pyth;
printf ("a = ");
scanf ("%lf", &pyth.a);
printf ("b = ");
scanf ("%lf", &pyth.b);
if ((error = pthread_create (&tid, NULL, thread_pyth, &pyth)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("c = %g\n", pyth.c);
double d[3];
printf ("x = ");
scanf ("%lf", &d[0]);
printf ("y = ");
scanf ("%lf", &d[1]);
if ((error = pthread_create (&tid, NULL, thread_aver, d)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("z = %g\n", d[2]);
int* n = malloc (sizeof (int));
*n = 1234;
if ((error = pthread_create (&tid, NULL, thread_show, n)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
/*
free (n);
*/
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
free (n);
return 0;
}
等待執行緒
====
int pthread_join (pthread_t thread, void** retval);
等待 thread 引數所標識的執行緒結束,成功返回 0,失敗返回錯誤碼。
範例:ret.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
/*
static double s;
s = PAI * r * r;
return &s;
*/
double* s = malloc (sizeof (double));
*s = PAI * r * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
注意從執行緒過程函式中返回值的方法:
1) 執行緒過程函式將所需返回的內容放在一塊記憶體中,
返回該記憶體的地址,保證這塊記憶體在函式返回,即執行緒結束,以後依然有效;
2) 若 retval 引數非 NULL,則 pthread_join 函式將執行緒過程函式所返回的指標,
拷貝到該引數所指向的記憶體中;
3) 若執行緒過程函式所返回的指標指向動態分配的記憶體,
則還需保證在用過該記憶體之後釋放之。
獲取執行緒自身的 ID
=========
pthread_t pthread_self (void);
成功返回呼叫執行緒的 ID,不會失敗。
比較兩個執行緒的 ID
=========
int pthread_equal (pthread_t t1, pthread_t t2);
若引數 t1 和 t2 所標識的執行緒 ID 相等,則返回非零,否則返回 0。
某些實現的 pthread_t 不是 unsigned long int 型別,
可能是結構體型別,無法通過“==”判斷其相等性。
範例:equal.c
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_t g_main;
void* ismain (void* arg) {
// if (pthread_self () == g_main)
if (pthread_equal (pthread_self (), g_main))
printf ("我是主執行緒!\n");
else
printf ("我不是主執行緒!\n");
return NULL;
}
int main (void) {
g_main = pthread_self ()
ismain (NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, ismain, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
return 0;
}
終止執行緒
====
1) 從執行緒過程函式中 return。
2) 呼叫 pthread_exit 函式。
void pthread_exit (void* retval);
retval - 和執行緒過程函式的返回值語義相同。
注意:在任何執行緒中呼叫 exit 函式都將終止整個程序。
範例:exit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define PAI 3.14159
void* thread_area (void* arg) {
double r = *(double*)arg;
double* s = malloc (sizeof (double));
// exit (0);
*s = PAI * r * r;
pthread_exit (s); // <==> return s;
*s = 2 * PAI * r;
return s;
}
int main (void) {
printf ("r = ");
double r;
scanf ("%lf", &r);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_area, &r);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
double* s;
if ((error = pthread_join (tid, (void**)&s)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("s = %g\n", *s);
free (s);
return 0;
}
執行緒執行軌跡
======
1) 同步方式 (非分離狀態):
建立執行緒之後呼叫 pthread_join 函式等待其終止,並釋放執行緒資源。
2) 非同步方式 (分離狀態):
無需建立者等待,執行緒終止後自行釋放資源。
int pthread_detach (pthread_t thread);
使 thread 引數所標識的執行緒進入分離 (DETACHED) 狀態。
處於分離狀態的執行緒終止後自動釋放執行緒資源,且不能被 pthread_join 函式等待。
成功返回 0,失敗返回錯誤碼。
範例:detach.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* thread_proc (void* arg) {
int i;
for (i = 0; i < 200; i++) {
putchar ('-');
usleep (50000);
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
// pthread_detach () 寫在 thread_proc () 裡面依然會被 pthread_join () 捕獲,無效果;
if ((error = pthread_detach (tid)) != 0) {
fprintf (stderr, "pthread_detach: %s\n", strerror (error));
return -1;
}
/*
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
*/
int i;
for (i = 0; i < 200; i++) {
putchar ('+');
usleep (100000);
}
printf ("\n");
return 0;
}
取消執行緒
====
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void elapse (void) {
size_t i;
for (i = 0; i < 800000000; ++i);
}
void* thread_proc (void* arg) {
/*
int error = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
if (error) {
fprintf (stderr, "pthread_setcancelstate: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*//*
int error = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
if (error) {
fprintf (stderr, "pthread_setcanceltype: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
*/
for (;;) {
printf ("執行緒:子在川上曰,逝者如斯夫。\n");
elapse ();
}
return NULL;
}
int main (void) {
setbuf (stdout, NULL);
printf ("按<回車>取消執行緒...\n");
pthread_t tid;
int error = pthread_create (&tid, NULL, thread_proc, NULL);
if (error) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
getchar ();
if ((error = pthread_cancel (tid)) != 0) {
fprintf (stderr, "pthread_cancel: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
printf ("已傳送取消請求,等待執行緒終止...\n");
if ((error = pthread_join (tid, NULL)) != 0) {
fprintf (stderr, "pthread_join: %s\n", strerror (error));
return -1;
}
printf ("執行緒已終止。\n");
return 0;
}
執行緒屬性
====
建立執行緒函式
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define __USE_GNU
#include <pthread.h>
int printattrs (pthread_attr_t* attr) {
printf("------- 執行緒屬性 -------\n");
int detachstate;
int error = pthread_attr_getdetachstate (attr, &detachstate);
if (error) {
fprintf (stderr, "pthread_attr_getdetachstate: %s\n", strerror (error));
return -1;
}
printf("分離狀態: %s\n",
(detachstate == PTHREAD_CREATE_DETACHED) ? "分離執行緒" :
(detachstate == PTHREAD_CREATE_JOINABLE) ? "可匯合執行緒" : "未知");
int scope;
if ((error = pthread_attr_getscope (attr, &scope)) != 0) {
fprintf (stderr, "pthread_attr_getscope: %s\n", strerror (error));
return -1;
}
printf ("競爭範圍: %s\n",
(scope == PTHREAD_SCOPE_SYSTEM) ? "系統級競爭" :
(scope == PTHREAD_SCOPE_PROCESS) ? "程序級競爭" : "未知");
int inheritsched;
if ((error = pthread_attr_getinheritsched (attr, &inheritsched)) != 0) {
fprintf (stderr, "pthread_attr_getinheritsched: %s\n", strerror (error));
return -1;
}
printf ("繼承特性: %s\n",
(inheritsched == PTHREAD_INHERIT_SCHED) ? "繼承呼叫屬性" :
(inheritsched == PTHREAD_EXPLICIT_SCHED) ? "顯式呼叫屬性" : "未知");
int schedpolicy;
if ((error = pthread_attr_getschedpolicy(attr, &schedpolicy)) != 0) {
fprintf (stderr, "pthread_attr_getschedpolicy: %s\n", strerror (error));
return -1;
}
printf ("排程策略: %s\n",
(schedpolicy == SCHED_OTHER) ? "普通" :
(schedpolicy == SCHED_FIFO) ? "先進先出" :
(schedpolicy == SCHED_RR) ? "輪轉" : "未知");
struct sched_param schedparam;
if ((error = pthread_attr_getschedparam (attr, &schedparam)) != 0) {
fprintf (stderr, "pthread_attr_getschedparam: %s\n", strerror (error));
return -1;
}
printf ("排程優先順序:%d\n", schedparam.sched_priority);
size_t guardsize;
if ((error = pthread_attr_getguardsize(attr, &guardsize)) != 0) {
fprintf (stderr, "pthread_attr_getguardsize: %s\n", strerror (error));
return -1;
}
printf ("棧尾警戒區:%u位元組\n", guardsize);
/*
void* stackaddr;
if ((error = pthread_attr_getstackaddr (attr, &stackaddr)) != 0) {
fprintf (stderr, "pthread_attr_getstackaddr: %s\n", strerror (error));
return -1;
}
printf ("棧地址: %p\n", stackaddr);
size_t stacksize;
if ((error = pthread_attr_getstacksize (attr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstacksize: %s\n", strerror (error));
return -1;
}
printf ("棧大小: %u位元組\n", stacksize);
*/
void* stackaddr;
size_t stacksize;
if ((error = pthread_attr_getstack (attr, &stackaddr, &stacksize)) != 0) {
fprintf (stderr, "pthread_attr_getstack: %s\n", strerror (error));
return -1;
}
printf ("棧地址: %p\n", stackaddr);
printf ("棧大小: %u位元組\n", stacksize);
printf("------------------------\n");
return 0;
}
void* thread_proc (void* arg) {
pthread_attr_t attr;
int error = pthread_getattr_np (pthread_self (), &attr);
if (error) {
fprintf (stderr, "pthread_getattr_np: %s\n", strerror (error));
exit (EXIT_FAILURE);
}
if (printattrs (&attr) < 0)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
return NULL;
}
int main (int argc, char* argv[]) {
int error;
pthread_attr_t attr, *pattr = NULL;
if (argc > 1) {
if (strcmp (argv[1], "-s")) {
fprintf (stderr, "用法:%s [-s]\n", argv[0]);
return -1;
}
if ((error = pthread_attr_init (&attr)) != 0) {
fprintf (stderr, "pthread_attr_init: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setdetachstate (&attr,
PTHREAD_CREATE_DETACHED)) != 0) {
fprintf (stderr, "pthread_attr_setdetachstate: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setinheritsched (&attr,
PTHREAD_EXPLICIT_SCHED)) != 0) {
fprintf (stderr, "pthread_attr_setinheritsched: %s\n", strerror (error));
return -1;
}
if ((error = pthread_attr_setstacksize (&attr, 4096*10)) != 0) {
fprintf (stderr, "pthread_attr_setstack: %s\n", strerror (error));
return -1;
}
pattr = &attr;
}
pthread_t tid;
if ((error = pthread_create (&tid, pattr, thread_proc, NULL)) != 0) {
fprintf (stderr, "pthread_create: %s\n", strerror (error));
return -1;
}
if (pattr)
if ((error = pthread_attr_destroy (pattr)) != 0) {
fprintf (stderr, "pthread_attr_destroy: %s\n", strerror (error));
return -1;
}
pause ();
return 0;
}