pthread_getattr_np(3) 作成されたスレッドの属性を取得する

書式

#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <pthread.h>
int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);


-pthread でコンパイルしてリンクする。

説明

pthread_getattr_np() 関数は、 attr が参照するスレッド属性オブジェクトを初期化し、 そのオブジェクトに実行中のスレッド thread の実際の属性値を 格納して返す。

返される属性値は、pthread_create(3) でスレッドを作成する際に 使われたattr オブジェクトで渡された属性値と異なる場合がある。 特に、以下の属性は異なる場合がある。

*
detach state. join 可能なスレッドは作成後に自分自身を 切り離す (detach する) ことができるからである。
*
スタックサイズ。 スレッドの実装によって適切な境界に揃えられる可能があるためである。
*
guard size. スレッドの実装によりページサイズの倍数に切り上げられたり、 アプリケーションが自分でスタックを割り当てる場合には無視される (0 として扱われる) ことがあるからである。

さらに、スレッドを作成する際に使用されたスレッド属性オブジェクトで スタックアドレスが設定されていなかった場合、 返されたスレッド属性オブジェクトではスレッドの実装がそのスレッドに 割り当てた実際のスタックアドレスが報告される。

pthread_getattr_np() が返したスレッド属性オブジェクトが 必要なくなった際には、 pthread_attr_destroy(3) を使って そのオブジェクトを破棄すべきである。

返り値

成功すると、この関数は 0 を返す。 エラーの場合、 0 以外のエラー番号を返す。

エラー

ENOMEM
メモリが十分になかった。

さらに、 thread がメインスレッドを参照している場合には、 pthread_getattr_np() は内部で行われる様々な呼び出しでの エラーで失敗する可能性がある。 /proc/self/maps がオープンできない場合には fopen(3) でエラーが発生し、リソース上限 RLIMIT_STACK が サポートされていない場合には getrlimit(2) でエラーが発生する。

バージョン

この関数は glibc バージョン 2.2.3 以降で利用できる。

準拠

この関数は非標準の GNU による拡張である。 そのため、名前に "_np" (nonportable; 移植性がない) という接尾辞が 付いている。

以下のプログラムは pthread_getattr_np() の使用例を示したものである。 このプログラムは、スレッドを作成し、それから pthread_getattr_np() を使ってそのスレッドの属性 guard size、 スタックアドレス、スタックサイズを取得し表示する。 コマンドライン引き数での指定で、スレッドを作成する際に 上記の属性にデフォルト値以外の値を設定することができる。 下記のシェルのセッションはこのプログラムの使用例である。

最初の実行例は、デフォルトの属性でスレッドが作成されている (x86-32 システム上で実行)。

$ ulimit -s      # No stack limit ==> default stack size is 2MB
unlimited
$ ./a.out
Attributes of created thread:
        Guard size          = 4096 bytes
        Stack address       = 0x40196000 (EOS = 0x40397000)
        Stack size          = 0x201000 (2101248) bytes

次の実行例では、guard size が指定された場合、 guard size はシステムのページサイズの倍数に切り上げられることが分かる (x86-32 ではシステムのページサイズは 4096 バイトである)。

$ ./a.out -g 4097
Thread attributes object after initializations:
        Guard size          = 4097 bytes
        Stack address       = (nil)
        Stack size          = 0x0 (0) bytes
Attributes of created thread:
        Guard size          = 8192 bytes
        Stack address       = 0x40196000 (EOS = 0x40397000)
        Stack size          = 0x201000 (2101248) bytes

最後の実行例では、プログラムでスレッド用のスタックを手動で割り当てている。 この場合には、guard size 属性は無視される。

$ ./a.out -g 4096 -s 0x8000 -a
Allocated thread stack at 0x804d000
Thread attributes object after initializations:
        Guard size          = 4096 bytes
        Stack address       = 0x804d000 (EOS = 0x8055000)
        Stack size          = 0x8000 (32768) bytes
Attributes of created thread:
        Guard size          = 0 bytes
        Stack address       = 0x804d000 (EOS = 0x8055000)
        Stack size          = 0x8000 (32768) bytes

プログラムのソース

#define _GNU_SOURCE     /* To get pthread_getattr_np() declaration */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void
display_stack_related_attributes(pthread_attr_t *attr, char *prefix)
{
    int s;
    size_t stack_size, guard_size;
    void *stack_addr;
    s = pthread_attr_getguardsize(attr, &guard_size);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getguardsize");
    printf("%sGuard size          = %d bytes\n", prefix, guard_size);
    s = pthread_attr_getstack(attr, &stack_addr, &stack_size);
    if (s != 0)
        handle_error_en(s, "pthread_attr_getstack");
    printf("%sStack address       = %p", prefix, stack_addr);
    if (stack_size > 0)
        printf(" (EOS = %p)", (char *) stack_addr + stack_size);
    printf("\n");
    printf("%sStack size          = 0x%x (%d) bytes\n",
            prefix, stack_size, stack_size);
}
static void
display_thread_attributes(pthread_t thread, char *prefix)
{
    int s;
    pthread_attr_t attr;
    s = pthread_getattr_np(thread, &attr);
    if (s != 0)
        handle_error_en(s, "pthread_getattr_np");
    display_stack_related_attributes(&attr, prefix);
    s = pthread_attr_destroy(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_destroy");
}
static void *           /* Start function for thread we create */
thread_start(void *arg)
{
    printf("Attributes of created thread:\n");
    display_thread_attributes(pthread_self(), "\t");
    exit(EXIT_SUCCESS);         /* Terminate all threads */
}
static void
usage(char *pname, char *msg)
{
    if (msg != NULL)
        fputs(msg, stderr);
    fprintf(stderr, "Usage: %s [-s stack-size [-a]]"
            " [-g guard-size]\n", pname);
    fprintf(stderr, "\t\t-a means program should allocate stack\n");
    exit(EXIT_FAILURE);
}
static pthread_attr_t *   /* Get thread attributes from command line */
get_thread_attributes_from_cl(int argc, char *argv[],
                              pthread_attr_t *attrp)
{
    int s, opt, allocate_stack;
    long stack_size, guard_size;
            void *stack_addr;
    pthread_attr_t *ret_attrp = NULL;   /* Set to attrp if we initialize
                                           a thread attributes object */
    allocate_stack = 0;
    stack_size = -1;
    guard_size = -1;
    while ((opt = getopt(argc, argv, "ag:s:")) != -1) {
        switch (opt) {
        case 'a':   allocate_stack = 1;                     break;
        case 'g':   guard_size = strtoul(optarg, NULL, 0);  break;
        case 's':   stack_size = strtoul(optarg, NULL, 0);  break;
        default:    usage(argv[0], NULL);
        }
    }
    if (allocate_stack && stack_size == -1)
        usage(argv[0], "Specifying -a without -s makes no sense\n");
    if (argc > optind)
        usage(argv[0], "Extraneous command-line arguments\n");
    if (stack_size >= 0 || guard_size > 0) {
        ret_attrp = attrp;
        s = pthread_attr_init(attrp);
        if (s != 0)
            handle_error_en(s, "pthread_attr_init");
    }
    if (stack_size >= 0) {
        if (!allocate_stack) {
            s = pthread_attr_setstacksize(attrp, stack_size);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setstacksize");
        } else {
            s = posix_memalign(&stack_addr, sysconf(_SC_PAGESIZE),
                               stack_size);
            if (s != 0)
                handle_error_en(s, "posix_memalign");
            printf("Allocated thread stack at %p\n\n", stack_addr);
            s = pthread_attr_setstack(attrp, stack_addr, stack_size);
            if (s != 0)
                handle_error_en(s, "pthread_attr_setstacksize");
        }
    }
    if (guard_size >= 0) {
        s = pthread_attr_setguardsize(attrp, guard_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstacksize");
    }
    return ret_attrp;
}
int
main(int argc, char *argv[])
{
    int s;
    pthread_t thr;
    pthread_attr_t attr;
    pthread_attr_t *attrp = NULL;    /* Set to &attr if we initialize
                                        a thread attributes object */
    attrp = get_thread_attributes_from_cl(argc, argv, &attr);
    if (attrp != NULL) {
        printf("Thread attributes object after initializations:\n");
        display_stack_related_attributes(attrp, "\t");
        printf("\n");
    }
    s = pthread_create(&thr, attrp, &thread_start, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");
    if (attrp != NULL) {
        s = pthread_attr_destroy(attrp);
        if (s != 0)
            handle_error_en(s, "pthread_attr_destroy");
    }
    pause();    /* Terminates when other thread calls exit() */
}

この文書について

この man ページは Linux man-pages プロジェクトのリリース 3.65 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。