يدعم المخزن المؤقت الحلقة المفردة ذات المنتجات الواحدة (MPSC) الخالية من القفل والذي يدعم عمليات النطاق المتجاورة والتي يمكن استخدامها بشكل مناسب لتمرير الرسائل. تتم كتابة التنفيذ في C11 وتوزيعه بموجب ترخيص BSD من البوطين.
int ringbuf_setup(ringbuf_t *rbuf, unsigned nworkers, size_t length)
rbuf هو مؤشر إلى كائن المخزن المؤقت الدائري المعتمة. المتصل مسؤول عن تخصيص مساحة لهذا الكائن. عادةً ما يتم تخصيص الكائن ديناميكيًا في حالة استخدام مؤشرات الترابط أو محفوظة في ذاكرة مشتركة تم حظرها في حالة استخدام العمليات. يجب الحصول على حجم التخصيص للكائن باستخدام دالة ringbuf_get_sizes . يعود 0 على النجاح و -1 على الفشل. void ringbuf_get_sizes(unsigned nworkers, size_t *ringbuf_obj_size, size_t *ringbuf_worker_size)
ringbuf_t غير شفاف ، واختياري ، هياكل ringbuf_worker_t . يعتمد حجم بنية ringbuf_t على عدد العمال ، المحددة بواسطة معلمة nworkers . ringbuf_worker_t *ringbuf_register(ringbuf_t *rbuf, unsigned i)
i رقم عامل ، بدءًا من الصفر (أي أن يكون nworkers في الإعداد المستخدمة في الإعداد). عند النجاح ، إرجاع مؤشر إلى ringbuf_worker_t المهيكلة ، وهو جزء من كتلة ذاكرة ringbuf_t . على الفشل ، إرجاع NULL . void ringbuf_unregister(ringbuf_t *rbuf, ringbuf_worker_t *worker)
ssize_t ringbuf_acquire(ringbuf_t *rbuf, ringbuf_worker_t *worker, size_t len)
ringbuf_produce للإشارة إلى ذلك. لا يُسمح بالمكالمات المتداخلة. void ringbuf_produce(ringbuf_t *rbuf, ringbuf_worker_t *worker)
size_t ringbuf_consume(ringbuf_t *rbuf, size_t *offset)
ringbuf_release للإشارة إلى ذلك. void ringbuf_release(ringbuf_t *rbuf, size_t nbytes)
سيقوم المستهلك بإرجاع كتلة متجاورة من النطاقات المنتجة ، أي لن تُرجع مكالمة ringbuf_consume نطاقات جزئية. إذا كنت تفكر في النطاق المنتجة كرسالة ، فسيقوم المستهلك بإرجاع كتلة من الرسائل ، وينتهي دائمًا عند حدود الرسالة. يتيح لنا هذا السلوك استخدام تطبيق المخزن المؤقت لهذا الحلقة كقائمة انتظار للرسالة.
تم اختبار التنفيذ على نطاق واسع على جهاز X86 24 نورًا ، راجع اختبار الإجهاد للحصول على التفاصيل حول هذه التقنية. كما يوفر مثالاً على كيفية استخدام الآلية لتمرير الرسائل.
يوفر تطبيق المخزن المؤقت لهذا الحلقة دائمًا مجموعة متجاورة للمنتج. يتم تحقيقه من خلال التفاف المبكر إذا لم يكن النطاق المطلوب مناسبة في النهاية. الآثار المترتبة على ذلك هو أن مكالمة ringbuf_acquire قد تفشل إذا كان النطاق المطلوب أكبر من نصف حجم المخزن المؤقت. وبالتالي ، قد يكون من الضروري التأكد من أن حجم المخزن المؤقت الحلقة يبلغ ضعف حجم وحدة الإنتاج القصوى على الأقل.
تجدر الإشارة أيضًا إلى أن أحد مقايضات هذا التصميم هو أن المستهلك يقوم حاليًا بإجراء فحص O (N) على قائمة المنتجين.
المنتجون:
if (( w = ringbuf_register ( r , worker_id )) == NULL )
err ( EXIT_FAILURE , "ringbuf_register" )
...
if (( off = ringbuf_acquire ( r , w , len )) != -1 ) {
memcpy ( & buf [ off ], payload , len );
ringbuf_produce ( r , tls );
}مستهلك:
if (( len = ringbuf_consume ( r , & off )) != 0 ) {
process ( & buf [ off ], len );
ringbuf_release ( r , len );
}