سؤال

أنا فقط أتساءل عما إذا كان أي شخص يعرف بعض البرامج التعليمية الجيدة على الإنترنت لتطوير آلات الدولة. أو الكتب الإلكترونية؟

أبدأ العمل على آلات الدولة وأحتاج فقط إلى شيء عام لتبدأ.

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

المحلول

آلات الحالة بسيطة للغاية في C إذا كنت تستخدم مؤشرات الوظائف.

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

int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);

/* array and enum below must be in sync! */
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};

enum ret_codes { ok, fail, repeat};
struct transition {
    enum state_codes src_state;
    enum ret_codes   ret_code;
    enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
    {entry, ok,     foo},
    {entry, fail,   end},
    {foo,   ok,     bar},
    {foo,   fail,   end},
    {foo,   repeat, foo},
    {bar,   ok,     end},
    {bar,   fail,   end},
    {bar,   repeat, foo}};

#define EXIT_STATE end
#define ENTRY_STATE entry

int main(int argc, char *argv[]) {
    enum state_codes cur_state = ENTRY_STATE;
    enum ret_codes rc;
    int (* state_fun)(void);

    for (;;) {
        state_fun = state[cur_state];
        rc = state_fun();
        if (EXIT_STATE == cur_state)
            break;
        cur_state = lookup_transitions(cur_state, rc);
    }

    return EXIT_SUCCESS;
}

أنا لا أضع lookup_transitions() تعمل كما هو تافهة.

هذه هي الطريقة التي أقوم بها بآلات الدولة لسنوات.

نصائح أخرى

أفضل استخدام مؤشرات الوظيفة على العملاق switch البيانات ، ولكن على عكس إجابة QRDL عادة لا أستخدم رموز الإرجاع الصريحة أو جداول الانتقال.

أيضًا ، في معظم الحالات ، ستحتاج إلى أن تمر آلية على طول بيانات إضافية. إليك مثال على آلة الحالة:

#include <stdio.h>

struct state;
typedef void state_fn(struct state *);

struct state
{
    state_fn * next;
    int i; // data
};

state_fn foo, bar;

void foo(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = bar;
}

void bar(struct state * state)
{
    printf("%s %i\n", __func__, ++state->i);
    state->next = state->i < 10 ? foo : 0;
}

int main(void)
{
    struct state state = { foo, 0 };
    while(state.next) state.next(&state);
}

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

على سبيل المثال ، اضطررت إلى تحليل بروتوكول البيانات لـ بالقرب من كمبيوتر Balloon Flight, ، تم تخزين البيانات على بطاقة SD بتنسيق محدد (ثنائي) يحتاج إلى التحليل في ملف منفصل فاصلة. إن استخدام آلة الحالة لهذا المنطقي أكثر منطقية لأنه بناءً على ما هو جزء من المعلومات التالي هو أننا نحتاج إلى تغيير ما نحلوه.

الكود مكتوب باستخدام C ++ ، وهو متاح ك Parsefcu. كما ترون ، فإنه يكتشف أولاً الإصدار الذي نتحلقه ، ومن هناك يدخل جهازين مختلفتين.

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

في المثال الخاص بي ، لا تعد سلسلة GPS شرطًا لتسجيل الكمبيوتر ، لذلك قد يتم تخطي معالجة سلسلة GPS إذا تم العثور على بايتات السجل المفرد.

آلات الدولة بسيطة في الكتابة ، وبشكل عام أتابع القاعدة التي يجب أن تتدفق. يجب أن يتدفق المدخلات التي تمر عبر النظام بسهولة من الدولة إلى أخرى.

لسوء الحظ ، تتم كتابة معظم المقالات على آلات الدولة لـ C ++ أو اللغات الأخرى التي لديها دعم مباشر لتعدد الأشكال لأنه من الجيد تصميم الدول في تنفيذ FSM كطبقات مستمدة من فئة الحالة المجردة.

ومع ذلك ، من السهل جدًا تنفيذ آلات الحالة في C باستخدام عبارات التبديل لإرسال الأحداث إلى الحالات (بالنسبة إلى FSMs البسيطة ، فهي رمز إلى حد كبير) أو استخدام الجداول لتعيين الأحداث لتحولات الحالة.

هناك بعض المقالات البسيطة ، ولكن لائقة حول إطار أساسي لآلات الدولة في C هنا:

تعديل: الموقع "تحت الصيانة" ، روابط أرشيف الويب:

switch غالبًا ما تستخدم آلات الحالة المستندة إلى البيان مجموعة من وحدات الماكرو "لإخفاء" ميكانيكا switch بيان (أو استخدم مجموعة من if/then/else البيانات بدلا من أ switch) وجعل ما يصل إلى "لغة FSM" لوصف آلة الحالة في مصدر C. أنا شخصياً أفضل النهج القائم على الطاولة ، لكن هذا بالتأكيد له ميزة ، ويستخدم على نطاق واسع ، ويمكن أن يكون فعالًا خاصة بالنسبة لـ FSMs الأكثر بساطة.

تم تحديد أحد هذه الإطار من قبل ستيف رابين في "Game Programming GEMS" الفصل 3.0 (تصميم محرك AI قوي عام).

تمت مناقشة مجموعة مماثلة من وحدات الماكرو هنا:

إذا كنت مهتمًا أيضًا بتطبيقات آلة C ++ State ، فهناك الكثير مما يمكن العثور عليه. سأقوم بنشر مؤشرات إذا كنت مهتمًا.

النمذجة في الوقت الحقيقي الموجهة نحو الكائن كان رائعًا (نُشر في عام 1994 ويبيع الآن بأقل من 81 سنتًا ، بالإضافة إلى 3.99 دولار شحن).

هذا هو كل ما تحتاج إلى معرفته.

int state = 0;
while (state < 3)
{
    switch (state)
    {
        case 0:
            // Do State 0 Stuff
            if (should_go_to_next_state)
            {
                state++;
            }
            break;
        case 1:
            // Do State 1 Stuff    
            if (should_go_back) 
            {
                state--;
            }    
            else if (should_go_to_next_state) 
            {
                state++;
            }
            break;
        case 2:
            // Do State 2 Stuff    
            if (should_go_back_two) 
            {
                state -= 2;
            }    
            else if (should_go_to_next_state) 
            {
                state++;
            }
            break;
        default:
            break;
    }
}

هناك الكثير من الدروس لتعلم آلات الحالة اليدوية في C ، ولكن اسمحوا لي أيضًا أن أقترح برنامج التحويل البرمجي لآلة Ragel State:

http://www.complang.org/ragel/

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

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

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