Seluruh kebenaran tentang RTOS. Artikel # 19. Semaphores: pengantar dan layanan dasar



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 Data
Artikel # 17. Grup Bendera Acara: Pengantar dan Layanan Dasar
Artikel # 16. Sinyal
Artikel # 15. Partisi Memori: Layanan dan Struktur Data
Artikel # 14. Bagian memori: pengantar dan layanan dasar
Artikel # 13. Struktur data tugas dan panggilan API yang tidak didukung
Artikel # 12. Layanan untuk bekerja dengan tugas
Artikel # 11. Tugas: konfigurasi dan pengantar API
Artikel # 10. Penjadwal: fitur canggih dan pelestarian konteks
Artikel # 9. Penjadwal: implementasi
Artikel # 8. Nucleus SE: Desain dan Penyebaran Internal
Artikel # 7. Nucleus SE: Pendahuluan
Artikel # 6. Layanan RTOS lainnya
Artikel # 5. Interaksi tugas dan sinkronisasi
Artikel # 4. Tugas, pengalihan konteks, dan interupsi
Artikel # 3. Tugas dan Perencanaan
Artikel # 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 /* Number of semaphores in the system - 0-16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* Service call enabler */ #define NUSE_SEMAPHORE_RELEASE FALSE /* Service call enabler */ #define NUSE_SEMAPHORE_RESET FALSE /* Service call enabler */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* Service call enabler */ #define NUSE_SEMAPHORE_COUNT FALSE /* Service call enabler */ 

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 RTOS
Prototipe 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 SE
Panggilan 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 SE
Versi 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 RTOS
Prototipe 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 SE
Panggilan 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 SE
Kode 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; /* check whether a task is blocked */ /* on this semaphore */ 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.

Source: https://habr.com/ru/post/id429156/


All Articles