1. 程式人生 > >uc筆記11---執行緒管理,執行緒函式:建立、等待、獲取、比較、終止、取消, 執行緒屬性

uc筆記11---執行緒管理,執行緒函式:建立、等待、獲取、比較、終止、取消, 執行緒屬性

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;
        }