عدم قفل كائن المزامنة لـ pthread_cond_timedwait وpthread_cond_signal (على Linux)

StackOverflow https://stackoverflow.com/questions/1003190

سؤال

هل هناك أي جانب سلبي للاتصال بـ pthread_cond_timedwait دون إجراء قفل على كائن المزامنة المرتبط أولاً، وكذلك عدم استخدام قفل كائن المزامنة عند الاتصال بـ pthread_cond_signal ؟

في حالتي، لا يوجد أي شرط للتحقق منه، أريد سلوكًا مشابهًا جدًا لـ Java wait(long) and notify().

وفقا للوثائق، يمكن أن يكون هناك "سلوك جدولة غير متوقع".لست متأكدا ماذا يعني ذلك.

يبدو أن أحد البرامج يعمل بشكل جيد دون قفل كائنات المزامنة أولاً.

هل كانت مفيدة؟

المحلول

الأول ليس بخير:

ال pthread_cond_timedwait() و pthread_cond_wait() يجب حظر الوظائف على متغير الحالة.يجب أن يتم استدعاؤها مع Mutex مغلق بواسطة مؤشر ترابط الاتصال أو نتائج السلوك غير المحدد.

http://opengroup.org/onlinepubs/009695399/functions/pthread_cond_timedwait.html

والسبب هو أن التنفيذ قد يرغب في الاعتماد على قفل كائن المزامنة (mutex) لإضافتك بأمان إلى قائمة النادل.وقد ترغب في تحرير كائن المزامنة (mutex) دون التحقق أولاً من الاحتفاظ به.

والثاني مزعج:

إذا كان سلوك الجدولة المتوقعة مطلوبًا ، فسيتم قفل هذا mutex بواسطة استدعاء الخيط pthread_cond_signal() أو pthread_cond_broadcast().

http://www.opengroup.org/onlinepubs/007908775/xsh/pthread_cond_signal.html

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

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

راجع للشغل، في Java يجب أن يكون لديك القفل حتى تتمكن من إعلام () أو إعلام الكل ():

يجب استدعاء هذه الطريقة فقط بواسطة مؤشر ترابط هو مالك شاشة هذا الكائن.

http://java.sun.com/j2se/1.4.2/docs/api/Java/lang/Object.html#notify()

يشبه سلوك Java المتزامن {/}/wait/notifty/notifyAll pthread_mutex_lock/pthread_mutex_unlock/pthread_cond_wait/pthread_cond_signal/pthread_cond_broadcast، وليس عن طريق الصدفة.

نصائح أخرى

يناقش كتاب Butenhof الممتاز "البرمجة باستخدام خيوط POSIX" هذا الأمر مباشرةً في نهاية الفصل 3.3.3.

في الأساس، إرسال إشارة إلى condvar دون قفل كائن المزامنة هو a محتمل تحسين الأداء:إذا كان مؤشر ترابط الإشارة يحتوي على كائن المزامنة مقفلاً، فيجب على مؤشر الترابط الذي يستيقظ على condvar أن يحظر على الفور كائن المزامنة الذي قام مؤشر ترابط الإشارة بتأمينه حتى إذا كان مؤشر ترابط الإشارة لا يعدل أيًا من البيانات التي سيستخدمها مؤشر ترابط الانتظار.

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

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

وأعتقد أن هذا يجب أن تعمل (لاحظ كود مجربة):

// initialize a semaphore
sem_t sem;
sem_init(&sem,
    0, // not shared
    0  // initial value of 0
    );


// thread A
struct timespec tm;
struct timeb    tp;

const long sec      = msecs / 1000;
const long millisec = msecs % 1000;

ftime(&tp);
tp.time += sec;
tp.millitm += millisec;
if(tp.millitm > 999) {
    tp.millitm -= 1000;
    tp.time++;
}
tm.tv_sec  = tp.time;
tm.tv_nsec = tp.millitm * 1000000;

// wait until timeout or woken up
errno = 0;
while((sem_timedwait(&sem, &tm)) == -1 && errno == EINTR) {
    continue;
}

return errno == ETIMEDOUT; // returns true if a timeout occured


// thread B
sem_post(&sem); // wake up Thread A early

يجب أشار شروط خارج مزامنة كلما أمكن ذلك. كائنات المزامنة هي شر لا بد منه في البرمجة المتزامنة. استخدامها يؤدي إلى الخلاف الذي يسرق نظام الحد الأقصى للأداء أنه يمكن أن تستفيد من استخدام معالجات متعددة.

والغرض من مزامنة هو لحراسة الوصول إلى بعض المتغيرات المشتركة في البرنامج بحيث يتصرفون بالذرة. عندما يتم عملية الإشارات داخل مزامنة، فإنه يؤدي إلى إدراج مئات من دورات الجهاز غير ذات صلة في مزامنة التي لها علاقة مع حراسة البيانات المشتركة شيئا. يحتمل، فإنه يدعو من الفضاء المستخدم على طول الطريق إلى النواة.

والإيضاحات حول "السلوك جدولة يمكن التنبؤ به" في المعيار هي وهمية تماما.

وعندما نريد آلة لتنفيذ البيانات في التنبؤ به النظام، واضحة المعالم، وأداة لذلك هو تسلسل البيانات ضمن موضوع واحد التنفيذ: S1 ; S2. بيان S1 هو "المقرر" قبل S2.

ونحن نستخدم المواضيع عندما ندرك أن بعض الإجراءات مستقلة والنظام مواعيدها ليس مهما، وهناك مزايا الأداء إلى أن تتحقق، مثل المزيد من الاستجابة في الوقت المناسب للأحداث في الوقت الحقيقي أو الحوسبة على معالجات متعددة.

في بعض الأحيان عندما لا تصبح جدولة أوامر المهم بين المواضيع المتعددة، وهذا يندرج تحت مفهوم يسمى <م> الأولوية . الأولوية يحل ما يحدث أولا عندما يكون أحد البيانات N يحتمل أن يكون موعد تنفيذ. أداة أخرى لترتيب تحت خاصية تعدد والطابور. الأحداث التي وضعت في طابور واحد أو أكثر المواضيع وترابط خدمة واحد يعالج الأحداث في ترتيب قوائم الانتظار.

وخلاصة القول هي، وضع pthread_cond_broadcast ليست أداة مناسبة للسيطرة على الأمر بالتنفيذ. لن تجعل أمر الإعدام يمكن التنبؤ بها، بمعنى أن البرنامج لديه فجأة بالضبط نفس والسلوك استنساخه على كل منصة.

وتعني "السلوك جدولة يمكن التنبؤ بها" فقط. كنت لا تعرف ما الذي سيحدث. ولا تنفيذ. ويمكن أن تعمل كما هو متوقع. ويمكن أن تعطل التطبيق. ويمكن أن تعمل بشكل جيد لسنوات، ثم حالة تعارض يجعل لكم قرد التطبيق الذهاب. ويمكن أن الجمود.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top