
Semaphores disebutkan dalam salah satu artikel sebelumnya (# 5). Tugas utama mereka adalah mengendalikan akses ke sumber daya.
Artikel sebelumnya dalam seri:
Artikel # 18. Grup Bendera Acara: Layanan Pembantu dan Struktur DataArtikel # 17. Grup Bendera Acara: Pengantar dan Layanan DasarArtikel # 16. SinyalArtikel # 15. Partisi Memori: Layanan dan Struktur DataArtikel # 14. Bagian memori: pengantar dan layanan dasarArtikel # 13. Struktur data tugas dan panggilan API yang tidak didukungArtikel # 12. Layanan untuk bekerja dengan tugasArtikel # 11. Tugas: konfigurasi dan pengantar APIArtikel # 10. Penjadwal: fitur canggih dan pelestarian konteksArtikel # 9. Penjadwal: implementasiArtikel # 8. Nucleus SE: Desain dan Penyebaran InternalArtikel # 7. Nucleus SE: PendahuluanArtikel # 6. Layanan RTOS lainnyaArtikel # 5. Interaksi tugas dan sinkronisasiArtikel # 4. Tugas, pengalihan konteks, dan interupsiArtikel # 3. Tugas dan PerencanaanArtikel # 2. RTOS: Struktur dan mode waktu-nyata
Artikel # 1. RTOS: pengantar.
Menggunakan semaphores
Dalam Nucleus SE, semaphores didefinisikan pada tahap perakitan. Aplikasi dapat memiliki hingga 16 semaphore. Jika semaphore tidak ditentukan, kode panggilan layanan dan struktur data tidak termasuk dalam aplikasi.
Semaphore adalah penghitung tipe
U8 , akses yang dikontrol sedemikian rupa sehingga beberapa tugas dapat menggunakannya. Suatu tugas dapat menurunkan nilai penghitung semafor (menangkap) atau meningkatkannya (melepaskan). Mencoba untuk menangkap semafor dengan nilai nol dapat menyebabkan kesalahan atau penangguhan tugas, tergantung pada parameter panggilan API yang dipilih dan konfigurasi Nucleus SE.
Menyiapkan semafor
Jumlah semafor
Seperti kebanyakan objek Nucleus SE, pengaturan semaphores ditentukan oleh arahan
#define di
nuse_config.h . Parameter utama adalah
NUSE_SEMAPHORE_NUMBER , yang menentukan jumlah semafor dalam aplikasi. Secara default, parameter diatur ke 0 (semaphores tidak digunakan dalam aplikasi) dan dapat mengambil nilai apa pun hingga 16. Nilai yang salah akan menyebabkan kesalahan kompilasi, yang akan dihasilkan dengan memeriksa
nuse_config_check.h (file ini termasuk dalam
nuse_config.c , yang berarti ia mengkompilasi bersama dengan modul ini), sebagai hasilnya, arahan
#error akan
diaktifkan .
Memilih nilai bukan nol berfungsi sebagai aktivator utama untuk semafor. Parameter ini digunakan ketika mendefinisikan struktur data dan ukurannya tergantung pada nilainya (untuk lebih jelasnya, lihat lebih lanjut dalam artikel ini). Selain itu, nilai bukan nol mengaktifkan pengaturan API.
Aktifkan Panggilan API
Setiap fungsi API (panggilan utilitas) di Nucleus SE diaktifkan oleh arahan
#define di
nuse_config.h . Untuk semaphores, ini termasuk:
NUSE_SEMAPHORE_OBTAIN
NUSE_SEMAPHORE_RELEASE
NUSE_SEMAPHORE_RESET
NUSE_SEMAPHORE_INFORMATION
NUSE_SEMAPHORE_COUNT
Secara default, mereka diatur ke
FALSE , sehingga menonaktifkan setiap panggilan layanan dan memblokir masuknya kode yang mengimplementasikannya. Untuk mengatur semafor, Anda perlu memilih panggilan API yang diperlukan dan mengatur arahan terkait ke
TRUE .
Berikut ini adalah kutipan dari file
nuse_config.h default.
#define NUSE_SEMAPHORE_NUMBER 0 #define NUSE_SEMAPHORE_OBTAIN FALSE #define NUSE_SEMAPHORE_RELEASE FALSE #define NUSE_SEMAPHORE_RESET FALSE #define NUSE_SEMAPHORE_INFORMATION FALSE #define NUSE_SEMAPHORE_COUNT FALSE
Fungsi API yang diaktifkan jika tidak ada semafor dalam aplikasi akan menyebabkan kesalahan kompilasi (kecuali untuk
NUSE_Semaphore_Count () , yang selalu diaktifkan). Jika kode Anda menggunakan panggilan API yang belum diaktifkan, kesalahan tata letak akan terjadi karena kode implementasi tidak termasuk dalam aplikasi.
Utilitas panggilan semafor
Nucleus RTOS mendukung delapan panggilan layanan yang menyediakan fungsionalitas berikut:
- Menangkap semaphore. Nucleus SE diimplementasikan dalam fungsi NUSE_Semaphore_Obtain () .
- Lepaskan semaphore. Dalam Nucleus SE, ini diimplementasikan dalam fungsi NUSE_Semaphore_Release () .
- Mengembalikan semafor ke status yang tidak digunakan dengan melepaskan semua tugas yang dijeda (reboot). Nucleus SE diimplementasikan dalam NUSE_Semaphore_Reset () .
- Memberikan informasi tentang semaphore tertentu. Nucleus SE diimplementasikan dalam NUSE_Semaphore_Information () .
- Mengembalikan jumlah semafor yang dikonfigurasi dalam aplikasi. Nucleus SE diimplementasikan di NUSE_Semaphore_Count () .
- Menambahkan semaphore baru ke aplikasi. Nucleus SE tidak diimplementasikan.
- Menghapus semaphore dari aplikasi. Nucleus SE tidak diimplementasikan.
- Mengembalikan pointer ke semua semaphores. Nucleus SE tidak diimplementasikan.
Implementasi dari setiap panggilan layanan dijelaskan secara rinci di bawah ini.
Utilitas panggilan untuk menangkap dan melepaskan semaphores
Operasi mendasar yang dapat dilakukan pada semaphores adalah penangkapan dan pelepasan (penurunan dan peningkatan nilai). Nucleus RTOS dan Nucleus SE menyediakan dua panggilan API dasar untuk operasi ini.
Menangkap semaphore
Panggilan utilitas Nucleus RTOS untuk menangkap semafor sangat fleksibel dan memungkinkan Anda untuk menjeda tugas secara implisit atau dengan batas waktu tertentu jika operasi tidak dapat dilakukan saat ini, misalnya, jika Anda mencoba menangkap semafor dengan nilai nol. Nucleus SE menyediakan fitur yang sama, hanya jeda tugas yang opsional, dan batas waktu tidak diterapkan.
Tantangan untuk menangkap semaphore di Nucleus RTOSPrototipe panggilan layanan:
STATUS NU_Obtain_Semaphore (NU_SEMAPHORE * semaphore, ditangguhkan tanpa ditandatangani);Parameter:
semaphore - penunjuk ke blok kontrol semaphore yang disediakan oleh pengguna;
menangguhkan - parameter penangguhan tugas, dapat mengambil nilai
NU_NO_SUSPEND atau
NU_SUSPEND , serta nilai batas waktu.
Nilai pengembalian:
NU_SUCCESS - panggilan berhasil diselesaikan;
NU_UNAVAILABLE - semaphore memiliki nilai nol;
NU_INVALID_SEMAPHORE - pointer tidak valid ke semaphore;
NU_INVALID_SUSPEND - upaya untuk menjeda dari utas yang tidak terkait tugas;
NU_SEMAPHORE_WAS_RESET - semaphore direset saat tugas ditangguhkan.
Tantangan untuk menangkap semafor di Nucleus SEPanggilan API ini mendukung fungsionalitas inti API Nucleus RTOS.
Prototipe panggilan layanan:
STATUS NUSE_Semaphore_Obtain (NUSE_SEMAPHORE semaphore, U8 menangguhkan);Parameter:
semaphore - index (ID) dari semaphore yang digunakan;
menangguhkan - parameter penangguhan tugas, dapat berupa
NUSE_NO_SUSPEND atau
NUSE_SUSPEND .
Nilai pengembalian:
NUSE_SUCCESS - panggilan berhasil diselesaikan;
NUSE_UNAVAILABLE - semaphore memiliki nilai nol;
NUSE_INVALID_SEMAPHORE - indeks semaphore tidak valid;
NUSE_INVALID_SUSPEND - upaya untuk menjeda dari utas yang tidak terkait tugas atau ketika fungsionalitas pemblokiran API dinonaktifkan;
NUSE_SEMAPHORE_WAS_RESET - semaphore direset saat tugas ditangguhkan;
Menerapkan penangkapan semafor di Nucleus SEVersi kode fungsi
NUSE_Semaphore_Obtain () (setelah memeriksa parameter) dipilih menggunakan kompilasi bersyarat tergantung pada apakah dukungan untuk tugas pemblokiran (jeda) diaktifkan atau tidak. Pertimbangkan kedua opsi tersebut.
Jika kunci tidak diaktifkan, logika panggilan API ini cukup sederhana:
if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else /* semaphore unavailable */ { return_value = NUSE_UNAVAILABLE; }
Nilai penghitung semafor diperiksa, dan jika tidak sama dengan nol, menurun.
Jika penguncian tugas diaktifkan, logika menjadi lebih kompleks:
do { if (NUSE_Semaphore_Counter[semaphore] != 0) /* semaphore available */ { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else /* semaphore unavailable */ { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { /* block task */ NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4) | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);
Beberapa klarifikasi mungkin bermanfaat.
Kode ditempatkan dalam
loop do ... while , yang berjalan saat parameter
menangguhkan adalah
NUSE_SUSPEND .
Jika semaphore memiliki nilai bukan nol, maka berkurang. Variabel
penangguhan diatur ke
NUSE_NO_SUSPEND , dan panggilan API berakhir dan mengembalikan
NUSE_SUCESS .
Jika semafor adalah nol dan variabel
penangguhan disetel ke
NUSE_NO_SUSPEND , panggilan API mengembalikan
NUSE_UNAVAILABLE . Jika penangguhan ditetapkan ke
NUSE_SUSPEND , tugas akan dijeda. Setelah panggilan selesai (misalnya, ketika tugas dilanjutkan), jika nilai kembali adalah
NUSE_SUCCESS (yang menunjukkan bahwa tugas dilanjutkan setelah semaphore dirilis, dan bukan setelah reset), siklus dimulai dari awal.
Rilis Semaphore
Panggilan utilitas ke Nucleus RTOS API untuk membebaskan semaphore cukup sederhana: nilai penghitung semaphore meningkat dan pesan sukses dikembalikan. Nucleus SE menyediakan fitur yang sama, tetapi dengan pengecekan overflow tambahan.
Tantang untuk merilis semaphores di Nucleus RTOSPrototipe panggilan layanan:
STATUS NU_Release_Semaphore (NU_SEMAPHORE * semaphore);Parameter:
semaphore - pointer ke blok kontrol semaphore yang disediakan oleh pengguna.
Nilai pengembalian:
NU_SUCCESS - panggilan berhasil diselesaikan;
NU_INVALID_SEMAPHORE - Pointer semaphore
tidak valid .
Tantangan untuk merilis semaphore di Nucleus SEPanggilan API ini mendukung fungsionalitas inti API Nucleus RTOS.
Prototipe panggilan layanan:
STATUS NUSE_Semaphore_Release (NUSE_SEMAPHORE semaphore);Parameter:
semaphore - Indeks (ID) dari semaphore yang dibebaskan.
Nilai pengembalian:
NUSE_SUCCESS - panggilan berhasil diselesaikan;
NUSE_INVALID_SEMAPHORE - indeks semaphore tidak valid;
NUSE_UNAVAILABLE - semaphore memiliki nilai 255 dan tidak dapat ditingkatkan.
Menerapkan rilis semaphore di Nucleus SEKode fungsi
NUSE_Semaphore_Release () (setelah memeriksa parameter) adalah umum, terlepas dari apakah kunci tugas diaktifkan atau tidak. Nilai penghitung semafor diperiksa, dan jika kurang dari 255, itu meningkat.
Kode lebih lanjut dipilih menggunakan kompilasi bersyarat jika dukungan untuk panggilan pemblokiran API (penangguhan tugas) diaktifkan:
NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { U8 index; NUSE_Semaphore_Blocking_Count[semaphore]--; for (index=0; index<NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;
Jika ada tugas yang ditangguhkan pada semafor ini, yang pertama dilanjutkan.
Artikel berikut akan menjelaskan panggilan API tambahan yang terkait dengan semaphores dan struktur datanya.
Tentang Pengarang: Colin Walls telah bekerja di industri elektronik selama lebih dari tiga puluh tahun, mencurahkan sebagian besar waktunya untuk firmware. Dia sekarang adalah seorang insinyur firmware di Mentor Embedded (sebuah divisi dari Mentor Graphics). Colin Walls sering berbicara di konferensi dan seminar, penulis berbagai artikel teknis dan dua buku tentang firmware. Tinggal di Inggris.
Blog profesional
Colin , email: colin_walls@mentor.com.