Saya membuat proyek kecil dalam campuran C dan C ++. Saya sedang membangun satu mesin negara-ish kecil di jantung salah satu utas pekerja saya.
Saya bertanya-tanya apakah Anda ahli di SO akan berbagi teknik desain mesin negara Anda.
CATATAN: Saya terutama setelah mencoba & menguji teknik implementasi.
DIPERBARUI: Berdasarkan semua input hebat yang dikumpulkan pada SO, saya telah menetapkan arsitektur ini:
c++
c
architecture
state-machine
jldupont
sumber
sumber
Jawaban:
Mesin negara yang saya rancang sebelumnya (C, bukan C ++) semuanya turun ke
struct
array dan loop. Struktur pada dasarnya terdiri dari keadaan dan peristiwa (untuk pencarian) dan fungsi yang mengembalikan keadaan baru, seperti:Kemudian Anda mendefinisikan negara dan acara Anda dengan definisi sederhana (
ANY
yang merupakan penanda khusus, lihat di bawah):Kemudian Anda mendefinisikan semua fungsi yang dipanggil oleh transisi:
Semua fungsi ini ditulis untuk tidak mengambil variabel dan mengembalikan negara baru untuk mesin negara. Dalam contoh ini variabel global digunakan untuk meneruskan informasi apa pun ke fungsi negara jika perlu.
Menggunakan global tidak seburuk kedengarannya karena FSM biasanya dikunci di dalam satu unit kompilasi dan semua variabel statis untuk unit itu (itulah sebabnya saya menggunakan tanda kutip di sekitar "global" di atas - mereka lebih dibagi dalam FSM, daripada benar-benar global). Seperti halnya semua global, ini membutuhkan perhatian.
Array transisi kemudian mendefinisikan semua transisi yang mungkin dan fungsi yang dipanggil untuk transisi tersebut (termasuk catch-all last):
Artinya adalah: jika Anda berada di
ST_INIT
negara bagian dan menerimaEV_KEYPRESS
acara tersebut, lakukan panggilan keGotKey
.Cara kerja FSM kemudian menjadi loop yang relatif sederhana:
Seperti disinggung di atas, perhatikan penggunaan
ST_ANY
sebagai wild-card, yang memungkinkan suatu peristiwa untuk memanggil fungsi tidak peduli keadaan saat ini.EV_ANY
juga bekerja dengan cara yang sama, memungkinkan acara apa pun di negara bagian tertentu untuk memanggil fungsi.Ini juga dapat menjamin bahwa, jika Anda mencapai akhir array transisi, Anda mendapatkan kesalahan yang menyatakan FSM Anda belum dibangun dengan benar (dengan menggunakan
ST_ANY/EV_ANY
kombinasi.Saya telah menggunakan kode yang serupa untuk ini pada banyak proyek komunikasi, seperti implementasi awal tumpukan komunikasi dan protokol untuk sistem embedded. Keuntungan besar adalah kesederhanaan dan kemudahan relatif dalam mengubah susunan transisi.
Saya tidak ragu akan ada abstraksi tingkat yang lebih tinggi yang mungkin lebih cocok saat ini tetapi saya curiga mereka semua akan menjadi seperti ini.
Dan, sebagai
ldog
pernyataan dalam komentar, Anda dapat menghindari global secara keseluruhan dengan melewatkan pointer struktur ke semua fungsi (dan menggunakannya dalam event loop). Ini akan memungkinkan beberapa mesin negara berjalan berdampingan tanpa gangguan.Cukup buat tipe struktur yang menyimpan data spesifik mesin (sebutkan minimal) dan gunakan itu sebagai ganti global.
Alasan saya jarang melakukan itu adalah hanya karena sebagian besar mesin negara yang saya tulis adalah tipe tunggal (satu kali, di-proses-mulai, membaca file konfigurasi misalnya), tidak perlu menjalankan lebih dari satu contoh . Tetapi memiliki nilai jika Anda perlu menjalankan lebih dari satu.
sumber
int (*fn)(void*);
tempatvoid*
penunjuk ke data yang setiap fungsi negara ambil sebagai parameter. Kemudian fungsi negara dapat menggunakan data atau mengabaikannya.Jawaban lain baik, tetapi implementasi yang sangat "ringan" yang saya gunakan ketika mesin negara sangat sederhana terlihat seperti:
Saya akan menggunakan ini ketika mesin negara cukup sederhana sehingga penunjuk fungsi & pendekatan tabel transisi terlalu berlebihan. Ini sering berguna untuk penguraian karakter per karakter atau kata per kata.
sumber
Maafkan saya karena melanggar setiap aturan dalam ilmu komputer, tetapi mesin negara adalah salah satu dari sedikit (saya dapat menghitung hanya dua) tempat
goto
pernyataan tidak hanya lebih efisien, tetapi juga membuat kode Anda lebih bersih dan lebih mudah dibaca. Karenagoto
pernyataan didasarkan pada label, Anda dapat memberi nama negara bagian Anda daripada harus melacak kekacauan angka atau menggunakan enum. Itu juga membuat kode lebih bersih karena Anda tidak memerlukan semua tambahan fungsi pointer fungsi atau pernyataan switch besar dan sementara loop. Apakah saya menyebutkan itu lebih efisien juga?Seperti apa bentuk mesin negara:
Anda mendapatkan ide umum. Intinya adalah bahwa Anda dapat mengimplementasikan mesin negara dengan cara yang efisien dan yang relatif mudah dibaca dan berteriak pada pembaca bahwa mereka melihat mesin negara. Perhatikan bahwa jika Anda menggunakan
goto
pernyataan, Anda harus tetap berhati-hati karena sangat mudah untuk menembak diri sendiri saat melakukannya.sumber
Anda dapat mempertimbangkan State Machine Compiler http://smc.sourceforge.net/
Utilitas open source yang luar biasa ini menerima deskripsi mesin negara dalam bahasa yang sederhana dan mengkompilasinya ke salah satu dari selusin bahasa - termasuk C dan C ++. Utilitas itu sendiri ditulis dalam Java, dan dapat dimasukkan sebagai bagian dari build.
Alasan untuk melakukan ini, alih-alih pengkodean tangan menggunakan pola GoF State atau pendekatan lainnya, adalah bahwa begitu mesin negara Anda dinyatakan sebagai kode, struktur yang mendasarinya cenderung menghilang di bawah beban pelat ketel yang perlu dihasilkan untuk mendukungnya. Menggunakan pendekatan ini memberi Anda pemisahan keprihatinan yang sangat baik, dan Anda menjaga struktur mesin negara Anda 'terlihat'. Kode yang dibuat secara otomatis masuk ke modul yang tidak perlu Anda sentuh, sehingga Anda dapat kembali dan bermain-main dengan struktur mesin negara tanpa memengaruhi kode pendukung yang telah Anda tulis.
Maaf, saya terlalu antusias, dan tidak diragukan lagi menunda semua orang. Tapi itu adalah utilitas kedudukan tertinggi, dan juga terdokumentasi dengan baik.
sumber
Pastikan untuk memeriksa karya Miro Samek (blog State Space , situs web State Machines & Tools ), yang artikel-artikelnya di C / C ++ Users Journal sangat bagus.
Situs web ini berisi implementasi (C / C ++) yang lengkap dalam sumber terbuka dan lisensi komersial kerangka mesin negara (QP Framework) , pengendali event (QEP) , alat pemodelan dasar (QM) dan alat tracing (QSpy) yang memungkinkan untuk menggambar mesin negara, membuat kode dan men-debug mereka.
Buku ini berisi penjelasan yang luas tentang apa / mengapa implementasi dan bagaimana menggunakannya dan juga bahan yang bagus untuk mendapatkan pemahaman tentang dasar-dasar mesin negara yang hirarki dan terbatas.
Situs web ini juga berisi tautan ke beberapa paket dukungan papan untuk penggunaan perangkat lunak dengan platform tertanam.
sumber
Saya telah melakukan sesuatu yang mirip dengan apa yang dijelaskan paxdiablo, hanya alih-alih susunan transisi keadaan / peristiwa, saya mengatur array fungsi 2-dimensi pointer, dengan nilai peristiwa sebagai indeks satu sumbu dan nilai kondisi saat ini sebagai yang lain. Kemudian saya hanya menelepon
state = state_table[event][state](params)
dan hal yang benar terjadi. Sel yang mewakili kombinasi keadaan / peristiwa tidak valid mendapatkan pointer ke fungsi yang mengatakannya, tentu saja.Jelas, ini hanya berfungsi jika nilai kondisi dan acara keduanya rentang yang berdekatan dan mulai dari 0 atau cukup dekat.
sumber
#define STATE_LIST() \STATE_LIST_ENTRY(state1)\STATE_LIST_ENTRY(state2)\...
(baris baru tersirat setelah masing-masing\
) tempat Anda mendefinisikan kembali entri makro ketika Anda menggunakan makro STATE_LIST. Contoh - membuat array nama negara:#define STATE_LIST_ENTRY(s) #s , \n const char *state_names[] = { STATE_LIST() };\n #undef STATE_LIST_ENTRY
. Beberapa bekerja untuk mengatur terlebih dahulu, tetapi ini sangat kuat. Tambahkan status baru -> dijamin tidak ketinggalan."Kerangka kerja" mesin negara C ++ berbasis template yang sangat bagus diberikan oleh Stefan Heinzmann dalam artikelnya .
Karena tidak ada tautan ke unduhan kode lengkap di artikel, saya telah mengambil kebebasan untuk menempelkan kode ke dalam proyek dan memeriksanya. Barang-barang di bawah ini diuji dan mencakup beberapa bagian kecil yang hilang tetapi cukup jelas.
Inovasi utama di sini adalah bahwa kompiler menghasilkan kode yang sangat efisien. Tindakan masuk / keluar kosong tidak ada biaya. Tindakan masuk / keluar yang tidak kosong diuraikan. Kompiler juga memverifikasi kelengkapan statechart. Tindakan yang hilang menghasilkan kesalahan tautan. Satu-satunya hal yang tidak tertangkap adalah yang hilang
Top::init
.Ini adalah alternatif yang sangat bagus untuk implementasi Miro Samek, jika Anda dapat hidup tanpa yang hilang - ini jauh dari implementasi UML Statechart yang lengkap, meskipun mengimplementasikan semantik UML dengan benar, sedangkan kode Samek dengan desain tidak menangani keluar / transisi / entri tindakan dalam urutan yang benar.
Jika kode ini berfungsi untuk apa yang perlu Anda lakukan, dan Anda memiliki kompiler C ++ yang layak untuk sistem Anda, itu mungkin akan berkinerja lebih baik daripada implementasi C / C ++ Miro. Kompiler menghasilkan implementasi mesin transisi, O (1) yang diratakan untuk Anda. Jika audit hasil rakitan mengonfirmasi bahwa optimisasi berfungsi seperti yang diinginkan, Anda mendekati kinerja teoritis. Bagian terbaik: ini relatif kecil, kode mudah dimengerti.
Kode tes berikut.
sumber
Teknik yang saya suka untuk mesin negara (setidaknya yang untuk kontrol program) adalah dengan menggunakan pointer fungsi. Setiap negara diwakili oleh fungsi yang berbeda. Fungsi mengambil simbol input dan mengembalikan penunjuk fungsi untuk status berikutnya. Monitor loop pengiriman pusat mengambil input berikutnya, mengumpankannya ke kondisi saat ini, dan memproses hasilnya.
Mengetiknya menjadi sedikit aneh, karena C tidak memiliki cara untuk menunjukkan jenis pointer fungsi mengembalikan diri mereka sendiri, sehingga fungsi negara kembali
void*
. Tetapi Anda dapat melakukan sesuatu seperti ini:Kemudian fungsi status individual Anda dapat mengaktifkan input mereka untuk memproses dan mengembalikan nilai yang sesuai.
sumber
Kasing paling sederhana
Poin: State bersifat privat, tidak hanya untuk unit kompilasi tetapi juga untuk event_handler. Kasing khusus dapat ditangani secara terpisah dari sakelar utama menggunakan konstruksi apa pun yang dianggap perlu.
Kasus yang lebih kompleks
Saat sakelar menjadi lebih besar dari beberapa layar penuh, pisahkan menjadi fungsi yang menangani masing-masing negara, menggunakan tabel keadaan untuk mencari fungsi secara langsung. Negara masih pribadi untuk pengendali acara. Fungsi state handler mengembalikan status berikutnya. Jika diperlukan beberapa acara masih dapat menerima perawatan khusus di pengendali acara utama. Saya suka melempar kejadian pseudo untuk masuk dan keluar negara dan mungkin memulai mesin negara:
Saya tidak yakin jika saya memakukan sintaks, terutama mengenai array pointer fungsi. Saya belum menjalankan semua ini melalui kompiler. Setelah ditinjau, saya perhatikan bahwa saya lupa untuk secara eksplisit membuang status berikutnya saat menangani kejadian pseudo (kurung (kosong) sebelum panggilan ke state_handler ()). Ini adalah sesuatu yang saya suka lakukan bahkan jika kompiler menerima kelalaian dalam diam. Ini memberitahu pembaca kode bahwa "ya, saya memang bermaksud memanggil fungsi tanpa menggunakan nilai kembali", dan mungkin menghentikan alat analisis statis dari peringatan tentang hal itu. Mungkin istimewa karena saya tidak ingat pernah melihat orang lain melakukan ini.
Poin: menambahkan sedikit kerumitan (memeriksa apakah keadaan berikutnya berbeda dari saat ini), dapat menghindari kode duplikat di tempat lain, karena fungsi penangan keadaan dapat menikmati peristiwa pseudo yang terjadi ketika keadaan dimasukkan dan dibiarkan. Ingatlah bahwa keadaan tidak dapat berubah ketika menangani peristiwa pseudo, karena hasil dari penangan keadaan dibuang setelah peristiwa ini. Anda tentu saja dapat memilih untuk mengubah perilaku.
Seorang penangan keadaan akan terlihat seperti ini:
Lebih rumit
Ketika unit kompilasi menjadi terlalu besar (apa pun yang Anda rasakan, saya harus mengatakan sekitar 1000 baris), letakkan masing-masing state handler dalam file terpisah. Ketika masing-masing pengendali keadaan menjadi lebih dari beberapa layar, pisahkan setiap acara dalam fungsi yang terpisah, mirip dengan cara sakelar keadaan dibagi. Anda dapat melakukan ini dalam beberapa cara, secara terpisah dari negara atau dengan menggunakan tabel bersama, atau menggabungkan berbagai skema. Beberapa dari mereka telah dibahas di sini oleh yang lain. Urutkan tabel Anda dan gunakan pencarian biner jika kecepatan merupakan persyaratan.
Pemrograman generik
Saya harus menyukai preprocessor untuk menangani masalah seperti menyortir tabel atau bahkan membuat mesin negara dari deskripsi, memungkinkan Anda untuk "menulis program tentang program". Saya percaya ini adalah apa yang orang Boost mengeksploitasi templat C ++, tapi saya menemukan sintaksis samar.
Tabel dua dimensi
Saya telah menggunakan tabel state / event di masa lalu, tetapi saya harus mengatakan bahwa untuk kasus yang paling sederhana, saya tidak menganggapnya perlu dan saya lebih suka kejelasan dan keterbacaan pernyataan switch bahkan jika itu melampaui satu layar penuh. Untuk kasus-kasus yang lebih kompleks, tabel-tabel dengan cepat lepas kendali seperti yang telah dicatat orang lain. Ungkapan-ungkapan yang saya sajikan di sini memungkinkan Anda untuk menambahkan banyak peristiwa dan menyatakan ketika Anda menginginkannya, tanpa harus mempertahankan tabel yang menggunakan memori (bahkan jika itu mungkin program memori).
Penolakan
Kebutuhan khusus dapat membuat idiom-idiom ini kurang berguna, tetapi saya merasa idiom-idiom ini sangat jelas dan dapat dipertahankan.
sumber
Sangat tidak teruji, tetapi menyenangkan untuk dikodekan, sekarang dalam versi yang lebih halus daripada jawaban asli saya; versi terbaru dapat ditemukan di mercurial.intuxication.org :
sm.h
contoh.c
sumber
Saya sangat menyukai jawaban paxdiable dan memutuskan untuk mengimplementasikan semua fitur yang hilang untuk aplikasi saya seperti variabel penjaga dan data spesifik mesin negara.
Saya mengunggah implementasi saya ke situs ini untuk berbagi dengan komunitas. Ini telah diuji menggunakan IAR Embedded Workbench untuk ARM.
https://sourceforge.net/projects/compactfsm/
sumber
Alat open source lain yang menarik adalah Yakindu Statechart Tools di statecharts.org . Itu menggunakan statecharts Harel dan dengan demikian menyediakan status hierarkis dan paralel dan menghasilkan kode C dan C ++ (serta Jawa). Itu tidak menggunakan perpustakaan tetapi mengikuti pendekatan 'kode biasa'. Kode ini pada dasarnya menerapkan struktur switch-case. Generator kode juga dapat dikustomisasi. Selain itu alat ini menyediakan banyak fitur lainnya.
sumber
Datang ke ini terlambat (seperti biasa) tetapi memindai jawaban sampai saat ini saya pikir ada sesuatu yang penting hilang;
Saya telah menemukan dalam proyek saya sendiri bahwa akan sangat membantu jika tidak memiliki fungsi untuk setiap kombinasi keadaan / acara yang valid. Saya sangat menyukai ide memiliki tabel 2D keadaan / peristiwa secara efektif. Tapi saya suka elemen tabel lebih dari sekedar fungsi pointer sederhana. Alih-alih saya mencoba mengatur desain saya sehingga pada dasarnya itu terdiri dari sekelompok elemen atau tindakan atom sederhana. Dengan begitu saya bisa membuat daftar unsur-unsur atom sederhana di setiap persimpangan negara / tabel acara saya. Idenya adalah bahwa Anda tidak perlu mendefinisikan massa fungsi N kuadrat (biasanya sangat sederhana). Mengapa ada sesuatu yang begitu rawan kesalahan, memakan waktu, sulit untuk ditulis, sulit dibaca, apa saja?
Saya juga menyertakan status baru opsional, dan penunjuk fungsi opsional untuk setiap sel dalam tabel. Pointer fungsi ada untuk kasus-kasus luar biasa di mana Anda tidak ingin hanya memecat daftar aksi atom.
Anda tahu Anda melakukannya dengan benar ketika Anda dapat mengekspresikan banyak fungsi yang berbeda, hanya dengan mengedit tabel Anda, tanpa kode baru untuk ditulis.
sumber
Alrght, saya pikir milik saya hanya sedikit berbeda dari milik orang lain. Sedikit lebih banyak pemisahan kode dan data daripada yang saya lihat di jawaban lainnya. Saya benar-benar membaca teori untuk menulis ini, yang mengimplementasikan bahasa Reguler penuh (tanpa ekspresi reguler, dengan sedih). Ullman, Minsky, Chomsky. Tidak bisa mengatakan saya mengerti semuanya, tetapi saya telah mengambil langsung dari para majikan lama: melalui kata-kata mereka.
Saya menggunakan pointer fungsi ke predikat yang menentukan transisi ke keadaan 'ya' atau keadaan 'tidak'. Ini memfasilitasi pembuatan akseptor keadaan terbatas untuk bahasa reguler yang Anda program dengan cara yang lebih mirip bahasa assembly. Tolong jangan diganggu oleh pilihan nama konyol saya. 'czek' == 'centang'. 'grok' == [lihatlah di Kamus Peretas].
Jadi untuk setiap iterasi, czek memanggil fungsi predikat dengan karakter saat ini sebagai argumen. Jika predikat mengembalikan true, karakter dikonsumsi (penunjuk maju) dan kami mengikuti transisi 'y' untuk memilih status berikutnya. Jika predikat mengembalikan false, karakter TIDAK dikonsumsi dan kami mengikuti transisi 'n'. Jadi setiap instruksi adalah cabang dua arah! Saya pasti sudah membaca The Story of Mel pada saat itu.
Kode ini datang langsung dari penerjemah postscript saya , dan berkembang menjadi bentuk saat ini dengan banyak bimbingan dari rekan-rekan di comp.lang.c. Karena postscript pada dasarnya tidak memiliki sintaks (hanya membutuhkan tanda kurung seimbang), Penerima Bahasa Reguler menyukai fungsi ini sebagai pengurai juga.
sumber
boost.org hadir dengan 2 implementasi bagan negara yang berbeda:
Seperti biasa, boost akan mengarahkan Anda ke neraka templat.
Perpustakaan pertama adalah untuk lebih banyak mesin keadaan kritis-kinerja. Pustaka kedua memberi Anda jalur transisi langsung dari UML Statechart ke kode.
Inilah pertanyaan SO yang meminta perbandingan antara keduanya di mana kedua penulis merespons.
sumber
Ini seri Ars OpenForum posting tentang sedikit agak rumit logika kontrol meliputi implementasi yang sangat mudah tindak sebagai mesin negara di C.
sumber
Melihat ini di suatu tempat
sumber
goto
menciptakan ketergantungan pada OS multitasking yang preemtive.Mengingat bahwa Anda menyiratkan Anda dapat menggunakan C ++ dan karenanya kode OO, saya akan menyarankan mengevaluasi pola 'GoF'state (GoF = Gang of Four, orang-orang yang menulis buku pola desain yang membawa pola desain menjadi pusat perhatian).
Ini tidak terlalu rumit dan banyak digunakan dan dibahas sehingga mudah untuk melihat contoh dan penjelasan secara online.
Kemungkinan besar juga akan dikenali oleh siapa pun yang menjaga kode Anda di kemudian hari.
Jika efisiensi adalah kekuatiran, perlu dilakukan benchmarking untuk memastikan bahwa pendekatan non-OO lebih efisien karena banyak faktor yang mempengaruhi kinerja dan tidak selalu hanya buruk, kode fungsional baik. Demikian pula, jika penggunaan memori merupakan kendala bagi Anda, maka perlu dilakukan lagi beberapa pengujian atau perhitungan untuk melihat apakah ini benar-benar akan menjadi masalah bagi aplikasi khusus Anda jika Anda menggunakan pola keadaan.
Berikut ini adalah beberapa tautan ke pola status 'Gof', seperti yang disarankan Craig:
sumber
Berikut adalah contoh Mesin Status Hingga untuk Linux yang menggunakan antrian pesan sebagai acara. Acara diletakkan di antrian dan ditangani secara berurutan. Keadaan berubah tergantung pada apa yang terjadi untuk setiap acara.
Ini adalah contoh untuk koneksi data dengan status seperti:
Satu fitur tambahan kecil yang saya tambahkan adalah cap waktu untuk setiap pesan / acara. Penangan acara akan mengabaikan acara yang terlalu lama (sudah kedaluwarsa). Ini bisa terjadi banyak di dunia nyata di mana Anda mungkin terjebak dalam kondisi yang tidak terduga.
Contoh ini berjalan di Linux, gunakan Makefile di bawah ini untuk mengkompilasi dan bermain-main dengannya.
state_machine.c
Makefile
sumber
Pertanyaan Anda cukup umum,
Berikut adalah dua artikel referensi yang mungkin berguna,
Implementasi Mesin Negara Tertanam
sumber
Saya telah menggunakan State Machine Compiler di proyek Java dan Python dengan sukses.
sumber
Ini adalah posting lama dengan banyak jawaban, tapi saya pikir saya akan menambahkan pendekatan saya sendiri ke mesin negara yang terbatas di C. Saya membuat skrip Python untuk menghasilkan kode kerangka C untuk sejumlah negara. Script itu didokumentasikan di GituHub di FsmTemplateC
Contoh ini didasarkan pada pendekatan lain yang pernah saya baca. Itu tidak menggunakan pernyataan goto atau beralih melainkan memiliki fungsi transisi dalam matriks pointer (tabel pencarian). Kode ini bergantung pada fitur multi-line makro dan C99 penginisialisasi besar (inisialisasi ditunjuk dan majemuk literal) jadi jika Anda tidak menyukai hal-hal ini, Anda mungkin tidak suka pendekatan ini.
Berikut ini adalah skrip Python dari a contoh pintu putar yang menghasilkan kerangka C-code menggunakan FsmTemplateC :
Header keluaran yang dihasilkan berisi typedefs:
eFsmTurnstileCheck
digunakan untuk menentukan apakah transisi diblokir denganEFSM_TURNSTILE_TR_RETREAT
, diizinkan untuk melanjutkanEFSM_TURNSTILE_TR_ADVANCE
, atau panggilan fungsi tidak didahului oleh transisi denganEFSM_TURNSTILE_TR_CONTINUE
.eFsmTurnstileState
hanyalah daftar negara.eFsmTurnstileInput
hanyalah daftar input.FsmTurnstile
struct adalah jantung dari mesin negara dengan cek transisi, meja fungsi lookup, kondisi saat ini, negara memerintahkan, dan alias untuk fungsi utama yang berjalan mesin.FsmTurnstile
hanya boleh dipanggil dari struct dan harus memiliki input pertama sebagai pointer untuk dirinya sendiri agar dapat mempertahankan keadaan persisten, gaya berorientasi objek.Sekarang untuk deklarasi fungsi di header:
Nama-nama fungsi ada dalam format
{prefix}_{from}_{to}
, di mana{from}
keadaan sebelumnya (saat ini) dan{to}
merupakan status berikutnya. Perhatikan bahwa jika tabel transisi tidak memungkinkan untuk transisi tertentu, penunjuk NULL bukannya penunjuk fungsi akan ditetapkan. Akhirnya, keajaiban terjadi dengan makro. Di sini kita membangun tabel transisi (matriks enum negara) dan fungsi transisi keadaan mencari tabel (matriks pointer fungsi):Saat membuat FSM, makro
FSM_EXAMPLE_CREATE()
harus digunakan.Sekarang, dalam kode sumber setiap fungsi transisi negara yang dinyatakan di atas harus diisi. The
FsmTurnstileFopts
struct dapat digunakan untuk melewatkan data ke / dari mesin negara. Setiap transisi harus diaturfsm->check
agar sama dengan baikEFSM_EXAMPLE_TR_RETREAT
untuk memblokirnya dari transisi atauEFSM_EXAMPLE_TR_ADVANCE
untuk memungkinkannya untuk transisi ke keadaan yang diperintahkan. Contoh yang berfungsi dapat ditemukan di (FsmTemplateC) [ https://github.com/ChisholmKyle/FsmTemplateC] .Berikut ini adalah penggunaan aktual yang sangat sederhana dalam kode Anda:
Semua bisnis header dan semua fungsi itu hanya untuk memiliki antarmuka yang sederhana dan cepat sangat berharga dalam pikiran saya.
sumber
Anda dapat menggunakan pustaka sumber terbuka OpenFST .
sumber
sumber
Saya pribadi menggunakan struct referensi diri dalam kombinasi dengan array pointer. Saya mengunggah tutorial di github beberapa waktu lalu, tautan:
https://github.com/mmelchger/polling_state_machine_c
Catatan: Saya menyadari bahwa utas ini cukup lama, tetapi saya berharap mendapatkan masukan dan pemikiran tentang desain mesin-negara serta mampu memberikan contoh untuk kemungkinan desain mesin-negara di C.
sumber
Anda dapat mempertimbangkan UML-state-machine-in-c , kerangka kerja state machine "ringan" di C. Saya telah menulis kerangka kerja ini untuk mendukung mesin state Finite dan mesin state Hierarchical . Bandingkan dengan tabel keadaan atau sakelar kasus sederhana, pendekatan kerangka kerja lebih scalable. Ini dapat digunakan untuk mesin negara terbatas sederhana untuk mesin negara hierarkis kompleks.
Mesin negara diwakili oleh
state_machine_t
struktur. Ini hanya mengandung dua anggota "Event" dan sebuah pointer ke "state_t".state_machine_t
harus menjadi anggota pertama dari struktur mesin negara Anda. misalnyastate_t
berisi penangan untuk negara dan juga penangan opsional untuk tindakan masuk dan keluar.Jika kerangka kerja dikonfigurasi untuk mesin status hierarkis maka
state_t
berisi pointer ke status induk dan anak.Kerangka menyediakan API
dispatch_event
untuk mengirimkan acara ke mesin negara danswitch_state
untuk memicu transisi negara.Untuk perincian lebih lanjut tentang cara menerapkan mesin status hierarkis, lihat repositori GitHub .
contoh kode,
https://github.com/kiishor/UML-State-Machine-in-C/blob/master/demo/simple_state_machine/readme.md https://github.com/kiishor/UML-State-Machine-in-C /blob/master/demo/simple_state_machine_enhanced/readme.md
sumber
Berikut adalah metode untuk mesin keadaan yang menggunakan makro sehingga setiap fungsi dapat memiliki set negara sendiri: https://www.codeproject.com/Articles/37037/Macros-to-simulate-multi-tasking-blocking-code -di
Itu berjudul "mensimulasikan multi tasking" tetapi itu bukan satu-satunya penggunaan.
Metode ini menggunakan panggilan balik untuk mengambil di setiap fungsi di mana ia tinggalkan. Setiap fungsi berisi daftar status unik untuk setiap fungsi. Central "idle loop" digunakan untuk menjalankan mesin status. "Idle loop" tidak tahu bagaimana mesin negara bekerja, itu adalah fungsi individu yang "tahu apa yang harus dilakukan". Untuk menulis kode untuk fungsi-fungsi, orang hanya membuat daftar status dan menggunakan makro untuk "menangguhkan" dan "melanjutkan". Saya menggunakan makro ini di Cisco ketika saya menulis Transceiver Library untuk switch Nexus 7000.
sumber