سؤال

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

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

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

المحلول

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

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

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

يمكنك معرفة LabView "استدعاء هذه الوظيفة عند حدوث xx". في C، أخبرك كود إيفاد الحدث الخاص بك "استدعاء هذه الوظيفة عند حدوث xx".

ما أحاول قوله (ضعيف؟) هو أن الهندسة المعمارية إطار الحدث ليست أصلية لتطبيق C / Linux. يجب ان يكون محاكاة بواسطة التعليمات البرمجية الخاصة بك عن طريق وجود مؤشر ترابط إيفاد رئيسي يعطي مظهر إطار محكم الحدث. إما أن تقوم بذلك يدويا، أو استخدم مكتبة حدث تقوم بذلك وراء الكواليس لإعطاء مظهر نموذج مدفوع الحدث. يأخذ LabView النهج الثاني، لذلك يبدو أنه لا يوجد رمز قيد التشغيل عندما تحدث أحداث، ولكن في الواقع يوجد رمز LabView الخاص ب C ++ يعمل بإدارة قوائم انتظار الأحداث. هذا لا يعني أنه مشغول في انتظار طوال الوقت، كما قلت قبل إجراء مكالمات النظام مثل تحديد والنوم الذي يمكن أن يستخدمه الرمز لإنتاج وقت وحدة المعالجة المركزية عندما لا يكون له عمل للقيام به، ولكن الكود لا يمكن ببساطة توقف عن التنفيذ.

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

 while not quitting
   If 10 seconds have elapsed, call tick()
   If Key has been Pressed
       call key() 
       add save the key to our key buffer
       If buffer now contains "foobar" call foobar() and clear buffer
   Wait()

إذا كانت جميع الأحداث التي تهتم بها هي أحداث مستوى النظام أو أحداث مستوى النظام، فيمكنك الانتظار () يمكن أن تخبر ببساطة أن تخبر Kernel "أيقظني عندما يحدث أحد هذه الأشياء" لذلك لا أحتاج إلى "الانتظار" مشغول " ، ولكن لا يمكنك مجرد إخبار kernel "استدعاء foobar () عندما يتم ضغط" foobar ". عليك أن يكون لديك رمز إرسال مستوى التطبيق الذي يحاكي بنية الحدث. لديك برنامج C نقطة دخول واحدة فقط من النواة لكل موضوع من التنفيذ. إذا نظرت إلى المكتبات التي توفر طرازات إرسال الأحداث، مثل QT، ستجد أنهم يعملون مثل هذا تحت غطاء محرك السيارة.

نصائح أخرى

انا يعجبني ليبيف لهذا النوع من الأشياء.

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

إذا كان كل ما يهتم به هو إدخال لوحة المفاتيح، C القياسية I / O هو ما تريد. يتم تخزين تدفقات الإدخال الافتراضية وسوف تشكك برنامجك حتى يتم استلام الإدخال. يستخدم scanf, getchar, ، أي شيء آخر في <stdio.h>.

إذا كنت تريد إدخال الماوس، فستحتاج إلى أن تكون أكثر تحديدا حول منصةك مثل C / C ++ لا يوجد لديه دعم أصلي للماوس أو النوافذ.

تشبيه جيد بنية حدث Labviews هو وظيفة "حدث سحب" Win32 GetMessage(). GetMessage() ينتظر إلى الأبد حتى يحدث حدث واجهة المستخدم الرسومية. هناك الكثير من الأحداث، حتى بالنسبة لكل نافذة طفلة (LabView: التحكم أو المؤشر) في Windows من LabView. GetMessage() يعود ببساطة في كل حدث، يجب إجراء تصفية غرامة (كما هو الحال في Labview) لاحقا، عادة باستخدام DispatchMessage() وإجراءات معالج الأحداث في النافذة WindowProc() مع أكثر أو أقل كبيرة switch() بيان.

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

إذا تم استخدام مهلة، فكر في ذلك MsgWaitForMultipleObjects() مع مقابض ملف صفر يسمى من قبل PeekMessage(). وبعد تنطبق حالة المهلة عندما لا يتم الوصول إلى أي حدث في فترة زمنية محددة.

في الواقع، يجب أن يكون بنية حدث LabViews داخل حلقة منفصلة. حلقة منفصلة هي موضوع. لبرمجة Win32 النموذجية، GetMessage() يستخدم في الخيط الرئيسي، ويتم إنشاء مؤشرات ترابط إضافية ("عامل") عن طريق تفاعل المستخدم حسب الحاجة.

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

بنية حدث LabViews لديها فرق كبير لغات البرمجة الأخرى: يمكن أن تحتوي أحداث LabView على مستهلكين متعددين! إذا تم استخدام هياكل الأحداث المتعددة، فكل شيء يستمر في العمل بشكل جيد (باستثناء الأحداث ذات القيم المرنة المنطقية). في Windows، يتم إرسال الأحداث إلى مؤشر ترابط محدد، معظمها إلى مؤشر ترابط Windows. لإطعام مؤشرات الترابط متعددة، يجب نشر الأحداث عدة مرات. مماثلة لغات البرمجة الأخرى. الأحداث التي يتم التعامل معها بواسطة شيء مشابه للوظائف ذات الصلة ل LABVEVEVEVEVEJES: إذا تلقى شخص ما الحدث، فسيكون خارج قائمة الانتظار.

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

يتم إدراك أحداث توزيع المستمعين المتعددين في Windows باستخدام DDE ولكن هذا مجرد العمليات من المواضيع. يتم تسجيل الدخول إلى مؤشر ترابط باستخدام DdeConnect() أو ما شابه، يتم دفع الأحداث إلى وظيفة رد الاتصال. (أن تكون أكثر دقة كيف يعمل Win32، GetMessage() يتلقى رسائل DDE، و DispathcMessage() في الواقع يدعو وظيفة رد الاتصال.)

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