pthread_create(3)

الاسم
pthread_create - إنشاء خيط جديد

المكتبة
مكتبة مسالك POSIX (libpthread، -lpthread)

موجز
#include <pthread.h>

int pthread_create(pthread_t *restrict thread,
                   const pthread_attr_t *_Nullable restrict attr,
                   typeof(void *(void *_Nullable)) *start_routine,
                   void *_Nullable restrict arg);

الوصف
الدالة pthread_create() تبدأ خيطًا جديدًا في العملية المستدعية. يبدأ الخيط الجديد التنفيذ باستدعاء start_routine()؛ يُمرر arg كوسيط وحيد لـ start_routine().

ينتهي الخيط الجديد بإحدى الطرق التالية:

•   يستدعي pthread_exit(3)، محددًا قيمة حالة خروج متاحة لخيط آخر في نفس العملية يستدعي pthread_join(3).

•   يعود من start_routine(). هذا يعادل استدعاء pthread_exit(3) بالقيمة المقدمة في عبارة return.

•   يُلغى (انظر pthread_cancel(3)).

•   أي من الخيوط في العملية يستدعي exit(3)، أو الخيط الرئيسي يعود من main(). هذا يسبب إنهاء جميع الخيوط في العملية.

الوسيط attr يشير إلى بنية pthread_attr_t تُستخدم محتوياتها وقت إنشاء الخيط لتحديد سمات الخيط الجديد؛ تُهيأ هذه البنية باستخدام pthread_attr_init(3) والدوال ذات الصلة. إذا كان attr NULL، فسيُُنشأ الخيط بسمات مبدئية.

قبل العودة، يخزن استدعاء ناجح لـ pthread_create() معرف الخيط الجديد في المخزن المؤقت المشار إليه بـ thread؛ يُستخدم هذا المعرف للإشارة إلى الخيط في الاستدعاءات اللاحقة لدوال pthreads الأخرى.

يرث الخيط الجديد نسخة من قناع الإشارات للخيط المنشئ (pthread_sigmask(3)). مجموعة الإشارات المعلقة للخيط الجديد فارغة (sigpending(2)). لا يرث الخيط الجديد مكدس الإشارات البديل للخيط المنشئ (sigaltstack(2)).

يرث الخيط الجديد بيئة النقطة العائمة للخيط المستدعي (fenv(3)).

القيمة المبدئية لساعة وقت وحدة المعالجة المركزية للخيط الجديد هي 0 (انظر pthread_getcpuclockid(3)).

  تفاصيل خاصة بلينكس
يرث الخيط الجديد نسخًا من مجموعات القدرات للخيط المستدعي (انظر capabilities(7)) وقناع التقارب لوحدة المعالجة المركزية (انظر sched_setaffinity(2)).

قيمة الإرجاع
عند النجاح، تُرجع pthread_create() 0؛ عند الخطأ، تُرجع رقم خطأ، ومحتويات *thread غير معرفة.

الأخطاء

EAGAIN
    موارد غير كافية لإنشاء خيط آخر.

EAGAIN
    وُجد حد يفرضه النظام على عدد الخيوط. هناك عدد من الحدود التي قد تسبب هذا الخطأ: حد المورد الناعم RLIMIT_NPROC (المُعيَّن عبر setrlimit(2))، الذي يحد عدد العمليات والخيوط لمعرف مستخدم حقيقي، وُصل إليه؛ حد النواة على مستوى النظام لعدد العمليات والخيوط، /proc/sys/kernel/threads-max، وُصل إليه (انظر proc(5))؛ أو الحد الأقصى لعدد معرفات العمليات، /proc/sys/kernel/pid_max، وُصل إليه (انظر proc(5)).

EINVAL
    إعدادات غير صالحة في attr.

EPERM
    لا يوجد إذن لتعيين سياسة الجدولة والمعاملات المُحدَّدة في attr.

السمات
للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).
الواجهة | السمة | القيمة
pthread_create() | سلامة الخيوط | MT-Safe

المعايير
POSIX.1-2008.

التاريخ
POSIX.1-2001.

ملاحظات
انظر pthread_self(3) لمزيد من المعلومات حول معرف الخيط المُرجَع في *thread بواسطة pthread_create(). ما لم تُستخدم سياسات جدولة زمن حقيقي، بعد استدعاء pthread_create()، يكون غير محدد أي خيط—المُستدعي أم الخيط الجديد—سَيُنفَّذ بعد ذلك.

قد يكون الخيط إما قابلًا للانضمام أو منفصلًا. إذا كان الخيط قابلًا للانضمام، فيمكن لخيط آخر استدعاء pthread_join(3) لانتظار إنهاء الخيط وجلب حالة خروجه. فقط عندما يُنضم إلى خيط قابل للانضمام مُنهى، تُحرَّر آخر موارده عائدةً إلى النظام. عندما يُنهى خيط منفصل، تُحرَّر موارده آليًا عائدةً إلى النظام: لا يمكن الانضمام إلى الخيط للحصول على حالة خروجه. جعل الخيط منفصلًا مفيد لبعض أنواع خيوط البرامج الخفية التي لا يحتاج التطبيق للاهتمام بحالة خروجها. مبدئيًا، يُنشأ خيط جديد في حالة قابلة للانضمام، ما لم يُضبط attr لإنشاء الخيط في حالة منفصلة (باستخدام pthread_attr_setdetachstate(3)).

تحت تنفيذ الخيوط NPTL، إذا كان حد المورد اللين RLIMIT_STACK عند وقت بدء البرنامج له أي قيمة غير "غير محدود"، فإنه يُحدد الحجم المبدئي لمكدس الخيوط الجديدة. باستخدام pthread_attr_setstacksize(3)، يمكن ضبط سمة حجم المكدس صراحةً في وسيط attr المُستخدم لإنشاء خيط، للحصول على حجم مكدس غير المبدئي. إذا ضُبط حد المورد RLIMIT_STACK على "غير محدود"، تُستخدم قيمة حسب المعمارية لحجم المكدس: 2 ميغابايت على معظم المعماريات؛ 4 ميغابايت على POWER وSparc-64.

العلل
في تنفيذ LinuxThreads المُتقادم، لكل خيط من خيوط العملية معرف عملية مختلف. هذا انتهاك لمواصفات خيوط POSIX، وهو مصدر العديد من حالات عدم المطابقة الأخرى للمعيار؛ انظر pthreads(7).

أمثلة
البرنامج أدناه يُوضح استخدام pthread_create()، بالإضافة إلى عدد من الدوال الأخرى في واجهة برمجة تطبيقات pthreads.

في التشغيل التالي، على نظام يُوفر تنفيذ الخيوط NPTL، الحجم المبدئي للمكدس هو القيمة المُعطاة بواسطة حد المورد "حجم المكدس":

    $ ulimit -s
    8192            # The stack size limit is 8 MB (0x800000 bytes)
    $ ./a.out hola salut servus
    Thread 1: top of stack near 0xb7dd03b8; argv_string=hola
    Thread 2: top of stack near 0xb75cf3b8; argv_string=salut
    Thread 3: top of stack near 0xb6dce3b8; argv_string=servus
    Joined with thread 1; returned value was HOLA
    Joined with thread 2; returned value was SALUT
    Joined with thread 3; returned value was SERVUS

في التشغيل التالي، البرنامج يضبط صراحةً حجم مكدس قدره 1 ميغابايت (باستخدام pthread_attr_setstacksize(3)) للخيوط المُنشأة:

    $ ./a.out -s 0x100000 hola salut servus
    Thread 1: top of stack near 0xb7d723b8; argv_string=hola
    Thread 2: top of stack near 0xb7c713b8; argv_string=salut
    Thread 3: top of stack near 0xb7b703b8; argv_string=servus
    Joined with thread 1; returned value was HOLA
    Joined with thread 2; returned value was SALUT
    Joined with thread 3; returned value was SERVUS

  مصدر البرنامج
    #include <ctype.h>
    #include <err.h>
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>

    struct thread_info {    /* Used as argument to thread_start() */
        pthread_t thread_id;        /* ID returned by pthread_create() */
        int       thread_num;       /* Application-defined thread # */
        char     *argv_string;      /* From command-line argument */
    };

    /* Thread start function: display address near top of our stack,
       and return upper-cased copy of argv_string.  */

    static void *
    thread_start(void *arg)
    {
        struct thread_info *tinfo = arg;
        char *uargv;

        printf("Thread %d: top of stack near %p; argv_string=%s\n",
               tinfo->thread_num, (void *) &tinfo, tinfo->argv_string);

        uargv = strdup(tinfo->argv_string);
        if (uargv == NULL)
            err(EXIT_FAILURE, "strdup");

        for (char *p = uargv; *p != '\0'; p++)
            *p = toupper(*p);

        return uargv;
    }

    int
    main(int argc, char *argv[])
    {
        int                 s, opt;
        void                *res;
        size_t              num_threads;
        ssize_t             stack_size;
        pthread_attr_t      attr;
        struct thread_info  *tinfo;

        /* The "-s" option specifies a stack size for our threads.  */

        stack_size = -1;
        while ((opt = getopt(argc, argv, "s:")) != -1) {
            switch (opt) {
            case 's':
                stack_size = strtoul(optarg, NULL, 0);
                break;

            default:
                fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
                        argv[0]);
                exit(EXIT_FAILURE);
            }
        }

        num_threads = argc - optind;

        /* Initialize thread creation attributes.  */

        s = pthread_attr_init(&attr);
        if (s != 0)
            errc(EXIT_FAILURE, s, "pthread_attr_init");

        if (stack_size > 0) {
            s = pthread_attr_setstacksize(&attr, stack_size);
            if (s != 0)
                errc(EXIT_FAILURE, s, "pthread_attr_setstacksize");
        }

        /* Allocate memory for pthread_create() arguments.  */

        tinfo = calloc(num_threads, sizeof(*tinfo));
        if (tinfo == NULL)
            err(EXIT_FAILURE, "calloc");

        /* Create one thread for each command-line argument.  */

        for (size_t tnum = 0; tnum < num_threads; tnum++) {
            tinfo[tnum].thread_num = tnum + 1;
            tinfo[tnum].argv_string = argv[optind + tnum];

            /* The pthread_create() call stores the thread ID into
               corresponding element of tinfo[].  */

            s = pthread_create(&tinfo[tnum].thread_id, &attr,
                               &thread_start, &tinfo[tnum]);
            if (s != 0)
                errc(EXIT_FAILURE, s, "pthread_create");
        }

        /* Destroy the thread attributes object, since it is no
           longer needed.  */

        s = pthread_attr_destroy(&attr);
        if (s != 0)
            errc(EXIT_FAILURE, s, "pthread_attr_destroy");

        /* Now join with each thread, and display its returned value.  */

        for (size_t tnum = 0; tnum < num_threads; tnum++) {
            s = pthread_join(tinfo[tnum].thread_id, &res);
            if (s != 0)
                errc(EXIT_FAILURE, s, "pthread_join");

            printf("Joined with thread %d; returned value was %s\n",
                   tinfo[tnum].thread_num, (char *) res);
            free(res);      /* Free memory allocated by thread */
        }

        free(tinfo);
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
getrlimit(2), pthread_attr_init(3), pthread_cancel(3), pthread_detach(3), pthread_equal(3), pthread_exit(3), pthread_getattr_np(3), pthread_join(3), pthread_self(3), pthread_setattr_default_np(3), pthreads(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.