pthread_cleanup_push(3)

الاسم
pthread_cleanup_push, pthread_cleanup_pop - دفع وسحب معالجات تنظيف إلغاء الخيط

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

موجز
#include <pthread.h>

void pthread_cleanup_push(typeof(void (void *)) *routine, void *arg);
void pthread_cleanup_pop(int execute);

الوصف
تتعامل هذه الدوال مع كومة معالجات تنظيف إلغاء الخيط للخيط المستدعي. معالج التنظيف هو دالة تُنفذ آليًا عند إلغاء خيط (أو في ظروف أخرى متنوعة موصوفة أدناه)؛ قد يقوم، على سبيل المثال، بفتح قفل كائن المزامنة (mutex) ليصبح متاحًا لخيوط أخرى في العملية.

تدفع الدالة pthread_cleanup_push() الروتين routine إلى أعلى كومة معالجات التنظيف. عندما يُستدعى routine لاحقًا، سيُعطى arg كمعامل له.

تزيل الدالة pthread_cleanup_pop() الروتين الموجود في أعلى كومة معالجات التنظيف، وتنفذه اختياريًا إذا كان execute غير صفري.

يُسحب معالج تنظيف الإلغاء من الكومة ويُنفذ في الظروف التالية:

•   عند إلغاء خيط، تُسحب جميع معالجات التنظيف المكدسة وتُنفذ بترتيب عكسي للترتيب الذي دُفعت به إلى الكومة.

•   عند إنهاء خيط باستدعاء pthread_exit(3)، تُنفذ جميع معالجات التنظيف كما هو موصوف في النقطة السابقة. (لا تُستدعى معالجات التنظيف إذا أنهى الخيط بتنفيذ return من دالة بدء الخيط.)

•   عندما يستدعي خيط pthread_cleanup_pop() بمعامل execute غير صفري، يُسحب معالج التنظيف الأعلى ويُنفذ.

يسمح POSIX.1 بتنفيذ pthread_cleanup_push() و pthread_cleanup_pop() كوحدات ماكرو تتوسع إلى نص يحتوي على '{' و '}'، على التوالي. لهذا السبب، يجب على المستدعي ضمان أن استدعاءات هذه الدوال مقترنة داخل نفس الدالة، وعلى نفس مستوى التداخل المعجمي. (بمعنى آخر، يُنشأ معالج التنظيف فقط أثناء تنفيذ قسم محدد من الكود.)

استدعاء longjmp(3) (siglongjmp(3)) يُنتج نتائج غير محددة إذا تم أي استدعاء لـ pthread_cleanup_push() أو pthread_cleanup_pop() دون الاستدعاء المطابق للزوج منذ أن مُلئ مخزن القفز بواسطة setjmp(3) (sigsetjmp(3)). وبالمثل، استدعاء longjmp(3) (siglongjmp(3)) من داخل معالج تنظيف يُنتج نتائج غير محددة ما لم يُملأ مخزن القفز أيضًا بواسطة setjmp(3) (sigsetjmp(3)) داخل المعالج.

قيمة الإرجاع
لا تعيد هذه الدوال قيمة.

الأخطاء
لا توجد أخطاء.

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

الإصدارات
في glibc، الدالتان pthread_cleanup_push() و pthread_cleanup_pop() هما منفذتان كوحدات ماكرو تتوسع إلى نص يحتوي على '{' و '}'، على التوالي. هذا يعني أن المتغيرات المعلنة ضمن نطاق الاستدعاءات المقترنة لهذه الدوال ستكون مرئية فقط ضمن ذلك النطاق.

يقول POSIX.1 أن تأثير استخدام return أو break أو continue أو goto لمغادرة كتلة محصورة بين pthread_cleanup_push() و pthread_cleanup_pop() مبكرًا هو غير محدد. يجب على التطبيقات المحمولة تجنب فعل ذلك.

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

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

أمثلة
يقدم البرنامج أدناه مثالًا بسيطًا لاستخدام الدوال الموصوفة في هذه الصفحة. ينشئ البرنامج خيطًا ينفذ حلقة محصورة بين pthread_cleanup_push() و pthread_cleanup_pop(). تزيد هذه الحلقة متغيرًا عامًا، cnt، مرة كل ثانية. اعتمادًا على وسائط سطر الأوامر المقدمة، يرسل الخيط الرئيسي للخيط الآخر طلب إلغاء، أو يضبط متغيرًا عامًا يتسبب في خروج الخيط الآخر من حلقته وإنهائه بشكل طبيعي (عن طريق تنفيذ return).

في جلسة الصدفة التالية، يرسل الخيط الرئيسي طلب إلغاء إلى الخيط الآخر:

    $ ./a.out;
    New thread started
    cnt = 0
    cnt = 1
    Canceling thread
    Called clean-up handler
    Thread was canceled; cnt = 0

مما سبق، نرى أن الخيط أُلغي، وأن معالج تنظيف الإلغاء استُدعي وأعاد ضبط قيمة المتغير العام cnt إلى 0.

في التشغيل التالي، يضبط البرنامج الرئيس متغيرًا عامًا يتسبب في إنهاء الخيط الآخر بشكل طبيعي:

    $ ./a.out x;
    New thread started
    cnt = 0
    cnt = 1
    Thread terminated normally; cnt = 2

مما سبق، نرى أن معالج التنظيف لم يُنفذ (لأن cleanup_pop_arg كانت 0)، وبالتالي لم تُعد قيمة cnt.

في التشغيل التالي، يضبط البرنامج الرئيس متغيرًا عامًا يتسبب في إنهاء الخيط الآخر بشكل طبيعي، ويوفر قيمة غير صفرية لـ cleanup_pop_arg:

    $ ./a.out x 1;
    New thread started
    cnt = 0
    cnt = 1
    Called clean-up handler
    Thread terminated normally; cnt = 0

في المثال أعلاه، نرى أنه على الرغم من أن الخيط لم يُلغَ، فقد نُفذ معالج التنظيف، لأن الوسيط المُعطى لـ pthread_cleanup_pop() كان غير صفري.

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

    static int done = 0;
    static int cleanup_pop_arg = 0;
    static int cnt = 0;

    static void
    cleanup_handler(void *arg)
    {
        printf("Called clean-up handler\n");
        cnt = 0;
    }

    static void *
    thread_start(void *arg)
    {
        time_t curr;

        printf("New thread started\n");

        pthread_cleanup_push(cleanup_handler, NULL);

        curr = time(NULL);

        while (!done) {
            pthread_testcancel();           /* A cancelation point */
            if (curr < time(NULL)) {
                curr = time(NULL);
                printf("cnt = %d\n", cnt);  /* A cancelation point */
                cnt++;
            }
        }

        pthread_cleanup_pop(cleanup_pop_arg);
        return NULL;
    }

    int
    main(int argc, char *argv[])
    {
        pthread_t thr;
        int s;
        void *res;

        s = pthread_create(&thr, NULL, thread_start, NULL);
        if (s != 0)
            errc(EXIT_FAILURE, s, "pthread_create");

        sleep(2);           /* Allow new thread to run a while */

        if (argc > 1) {
            if (argc > 2)
                cleanup_pop_arg = atoi(argv[2]);
            done = 1;

        } else {
            printf("Canceling thread\n");
            s = pthread_cancel(thr);
            if (s != 0)
                errc(EXIT_FAILURE, s, "pthread_cancel");
        }

        s = pthread_join(thr, &res);
        if (s != 0)
            errc(EXIT_FAILURE, s, "pthread_join");

        if (res == PTHREAD_CANCELED)
            printf("Thread was canceled; cnt = %d\n", cnt);
        else
            printf("Thread terminated normally; cnt = %d\n", cnt);
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
pthread_cancel(3)، pthread_cleanup_push_defer_np(3)، pthread_setcancelstate(3)، pthread_testcancel(3)، pthreads(7)

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

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

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