نظام إرسال الرسائل في C الذي لا يكسر التعرجات الصارمة والمحاذاة

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

سؤال

أنا أكتب نظام تحكم مضمن في ج أنه يتكون من مهام متعددة تقوم بإرسال رسائل إلى بعضها البعض (مصبوما شائعا إلى حد ما، وأعتقد!)، لكنني أواجه صعوبة في تصميم آلية مما يلي:

  • هو أنيق
  • هو عام
  • هو فعال نسبيا
  • الاكثر اهمية: هل منصة مستقلة (على وجه التحديد، لا تنتهك قضايا صارمة أو محاذاة)

من الناحية النظرية، أود أن تمثل كل نوع رسالة كتعريف منفصل من الهيكل، وأود أن نظاما مع الوظائف التالية (المبسطة):

void sendMsg(queue_t *pQueue, void *pMsg, size_t size);
void *dequeueMsg(queue_t *pQueue);

اين ا queue_t يشتمل على قائمة مرتبطة من العقد، كل منها char buf[MAX_SIZE] حقل. النظام الذي أقوم به ليس لديه malloc() التنفيذ، لذلك يجب أن تكون هناك مجموعة عالمية من العقد الحرة، ثم أحد الإجراءات التالية (المشكلات المتصورة في جريئة):

  1. sendMsg() هل memcpy من الرسالة الواردة في المخزن المؤقت لعقدة مجانية.
    فهمي هو أن هذا سيكون له مشاكل محاذاة ما لم يكن المتصل dequeueMsg() هل أبعد memcpy في قيمة العودة.
  2. أو سيكون هناك void *getFreeBuffer() وظيفة التي ترجع buf[] من العقدة المجانية التالية، والتي سوف يلقي المتصل (المرسل) إلى المؤشر المناسب إلى النوع.
    فهمي هو أن هذا سيكون لديه الآن مشاكل المحاذاة في الطريق، وما زال يتطلب memcpy بعد dequeueMsg() لتجنب مشاكل المحاذاة في الطريق للخروج.
  3. أو إعادة تعريف المخزن المؤقت في queue_t العقد (على سبيل المثال) uint32_t buf[MAX_SIZE].
    فهمي هو أن هذا ينتهك التعرج الصارم، وليس منصة مستقلة.

الخيار الآخر الوحيد الذي يمكنني رؤيته هو إنشاء اتحاد لجميع أنواع الرسائل جنبا إلى جنب مع char buf[MAX_SIZE], ، لكنني لا أعول هذا باعتباره "أنيق"!

لذلك سؤالي هو، كيف يفعل هذا الأمر بشكل صحيح؟

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

المحلول

الطريقة التي نتعامل معها هي أن تكون قائمتنا المجانية تتكون بالكامل من العقد المحاذاة. في الواقع، لدينا العديد من قوائم مجانية لأحجام مختلفة من العقدة، لذلك لدينا قوائم محاذاة على حدود 2 بايت، 4 بايت، و 16 بايت (منصتنا لا تهتم بالمواءمة أكبر من ناقلات SIMD واحد). يتم تقريب أي تخصيص لأحد هذه القيم ووضع عقدة محاذاة بشكل صحيح. لذلك، يقوم SENDMSG دائما بنسخ بياناته إلى عقدة محاذاة. منذ أن تكتب قائمة مجانية بنفسك، يمكنك تطبيق محاذاة بسهولة.

سنستخدم أيضا #pragma أو reclspec لإجبار مجموعة char buf [max_size] لتكون محاذاة إلى حدود كلمة على الأقل داخل بنية عقدة Queue_T.

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

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

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

نصائح أخرى

أنا لا أفهم لماذا 1 يقدم مشكلة محاذاة - طالما كل منها buf[MAX_SIZE] يتم محاذاة العنصر بأكبر نوع بدائي طبيعي يحدث في بنيات رسالتك (ربما 32 أو 64 بت)، ثم لا يهم ما هو محتويات كل نوع الرسالة؛ كما سيكون دائما محاذاة لهذا الحجم.

يحرر

في الواقع، إنه أكثر بساطة من ذلك. كما كل عنصر في قائمة انتظار الرسائل الخاصة بك هو MAX_SIZE في الطول، ثم افتراض أنك تبدأ كل رسالة في تكنولوجيا المعلومات الخاصة buf (أي لا يمكنك حملها إذا كانت الرسالة هي <max_size)، فستبدأ كل رسالة في قائمة الانتظار على حدود على الأقل كبيرة مثل نفسها، وبالتالي ستظل محاذاة بشكل صحيح.

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