pthread_cond_init(3)

الاسم
pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait, pthread_cond_destroy - عمليات على الشروط

موجز
#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_cond_init(pthread_cond_t *cond,
                      pthread_condattr_t *cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                      const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);

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

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

تهيئ الدالة pthread_cond_init() متغير الشرط cond، باستخدام سمات الشرط المحددة في cond_attr، أو السمات المبدئية إذا كان cond_attr فارغًا (NULL). لا يدعم تطبيق LinuxThreads أي سمات للشروط، وبالتالي يُتجاهل معامل cond_attr فعليًا.

يمكن أيضًا تهيئة متغيرات من النوع pthread_cond_t بشكل ثابت، باستخدام الثابت PTHREAD_COND_INITIALIZER.

تعيد الدالة pthread_cond_signal() تشغيل أحد الخيوط المنتظرة على متغير الشرط cond. إذا لم تكن أي خيوط تنتظر على cond، لا يحدث شيء. إذا كانت عدة خيوط تنتظر على cond، يُعاد تشغيل واحد منها بالضبط، ولكن لا يُحدد أي منها.

تعيد الدالة pthread_cond_broadcast() تشغيل جميع الخيوط المنتظرة على متغير الشرط cond. لا يحدث شيء إذا لم تكن أي خيوط تنتظر على cond.

تفتح الدالة pthread_cond_wait() كائن المزامنة mutex بشكل ذري (وفقًا لـ pthread_mutex_unlock()) وتنتظر الإشارة إلى متغير الشرط cond. يُعلق تنفيذ الخيط ولا يستهلك أي وقت من وحدة المعالجة المركزية حتى يُشار إلى متغير الشرط. يجب أن يكون mutex مقفلاً بواسطة الخيط المستدعي عند الدخول إلى pthread_cond_wait(). قبل العودة إلى الخيط المستدعي، تستعيد pthread_cond_wait() mutex (وفقًا لـ pthread_mutex_lock()).

يتم فتح كائن المزامنة والتعليق على متغير الشرط بشكل ذري. وبالتالي، إذا حصلت جميع الخيوط دائمًا على كائن المزامنة قبل الإشارة إلى الشرط، فهذا يضمن عدم إمكانية الإشارة إلى الشرط (وبالتالي تجاهله) بين الوقت الذي يقفل فيه الخيط كائن المزامنة والوقت الذي ينتظر فيه على متغير الشرط. انظر التحذيرات أدناه.

تفتح الدالة pthread_cond_timedwait() كائن المزامنة mutex بشكل ذري وتنتظر على cond، كما تفعل pthread_cond_wait()، ولكنها أيضًا تحدد مدة الانتظار. إذا لم يُشر إلى cond خلال المدة الزمنية المحددة بواسطة abstime، يُعاد الحصول على كائن المزامنة mutex وتُرجع pthread_cond_timedwait() الخطأ ETIMEDOUT. يحدد معامل abstime وقتًا مطلقًا، بنفس أصل time(2) و gettimeofday(2): abstime بقيمة 0 يتوافق مع 00:00:00 بتوقيت غرينتش، 1 يناير 1970.

تدمر الدالة pthread_cond_destroy() متغير شرط، محررة الموارد التي قد يحملها. يجب ألا تكون أي خيوط تنتظر على متغير الشرط عند الدخول إلى pthread_cond_destroy(). في تطبيق LinuxThreads، لا تُربط أي موارد بمتغيرات الشرط، وبالتالي لا تفعل pthread_cond_destroy() شيئًا فعليًا سوى التحقق من عدم وجود خيوط منتظرة على الشرط.

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

سلامة الإشارة غير المتزامنة
دوال الشرط ليست آمنة للإشارات غير المتزامنة، ولا ينبغي استدعاؤها من معالج إشارة. على وجه الخصوص، قد يؤدي استدعاء pthread_cond_signal() أو pthread_cond_broadcast() من معالج إشارة إلى توقف الخيط المستدعي (deadlock).

قيمة الإرجاع
ترجع جميع دوال متغير الشرط 0 عند النجاح ورمز خطأ غير صفري عند الخطأ.

الأخطاء
لا ترجع الدوال pthread_cond_init() و pthread_cond_signal() و pthread_cond_broadcast() و pthread_cond_wait() أي رمز خطأ أبدًا.

ترجع الدالة pthread_cond_timedwait() رموز الخطأ التالية عند الخطأ:

    ETIMEDOUT
        لم يُشر إلى متغير الشرط حتى المهلة المحددة بواسطة abstime.

ترجع الدالة pthread_cond_destroy() رمز الخطأ التالي عند الخطأ:

    EBUSY
        بعض الخيوط تنتظر حالياً على cond.

انظر أيضًا
pthread_condattr_init(3)، pthread_mutex_lock(3)، pthread_mutex_unlock(3)، gettimeofday(2)، nanosleep(2).

تحذيرات
استخدم تنفيذ الدوال المقدمة حتى glibc 2.25 قفلاً داخلياً للبيانات. لم يدعم هذا القفل توارث الأولوية وكان عرضة لانعكاس أولوية غير محدود، مرئي على نظام زمن حقيقي.

بعد إعادة كتابة التنفيذ في glibc 2.25، تغير استخدام القفل الداخلي. يُحصل القفل الداخلي دائماً بواسطة دوال الإشارة pthread_cond_signal() و pthread_cond_broadcast(). تحصل دالة الانتظار على القفل إذا قُطعت عملية الانتظار. يمكن أن يحدث القطع مثلاً بسبب مهلة محددة، ويُشار إليه بقيمة الخطأ ETIMEDOUTA، أو بإشارة مستقبلة، يُشار إليها بقيمة الخطأ EINTR.

مثال
اعتبر متغيرين مشتركين x و y، محميين بكائن المزامنة mut، ومتغير شرط cond يُشار إليه كلما أصبح x أكبر من y.

    int x,y; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

يُجرى الانتظار حتى يصبح x أكبر من y كالتالي:

    pthread_mutex_lock(&mut); while (x <= y) {         pthread_cond_wait(&cond, &mut); } /* operate on x and y */ pthread_mutex_unlock(&mut);

يجب أن تشير التعديلات على x و y التي قد تجعل x أكبر من y إلى الشرط إذا لزم الأمر:

    pthread_mutex_lock(&mut); /* modify x and y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut);

إذا أمكن إثبات أن خيطاً واحداً على الأكثر يحتاج إلى الإيقاظ (مثلاً، إذا كان هناك خيطان فقط يتواصلان عبر x و y)، يمكن استخدام pthread_cond_signal() كبديل أكثر كفاءة بقليل لـ pthread_cond_broadcast(). في حالة الشك، استخدم pthread_cond_broadcast().

لانتظار x ليصبح أكبر من y بمهلة 5 ثوانٍ، افعل:

    struct timeval now; struct timespec timeout; int retcode;  pthread_mutex_lock(&mut); gettimeofday(&now); timeout.tv_sec = now.tv_sec + 5; timeout.tv_nsec = now.tv_usec * 1000; retcode = 0; while (x <= y && retcode != ETIMEDOUT) {         retcode = pthread_cond_timedwait(&cond, &mut, &timeout); } if (retcode == ETIMEDOUT) {         /* timeout occurred */ } else {         /* operate on x and y */ } pthread_mutex_unlock(&mut);

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

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

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