セマフォ
セマフォ(sem
)オペレーティングシステムは、システムタスクとタスクの実装であり、タスク間の重要な資源の保護のための同期や相互排除のメカニズムを中断しました。マルチタスクシステムでは、多くの場合、タスク間の同期や相互排除を必要とし、セマフォは、ユーザー、この点でのサポートを提供することができます。
抽象、セマフォは非負整数、セマフォが取得されるたびに(あるpend
時間)、整数が1だけデクリメントされ、整数値場合0
、それはセマフォが非アクティブ状態にあることを示し、それはすべて、再度取得することができませんそのタスクはブロッキングステートに取得しようとします。セマフォは、通常、カウント値、カウント値がどのシステム資源数(カウント)を使用することができます。
一般的には、2つのセマフォ値があります。
- 0:なし蓄積
post
量信号演算し、このセマフォのブロッキングのタスクを有していてもよいです。 - 値:の1つまたは複数を示す
post
セマフォ操作を。
オペレーティング・システムは、より良い相互排除のための別の機構(ミューテックス)、相互排他ミューテックスの役割を提供するように、一般に、セマフォ、同期と相互に排他的ではないために使用される:ミューテックスは、優先度継承機構を有しますセマフォはまた、ミューテックスを持っている財産の所有者に加えて、我々はフォローアップを説明します、このメカニズムを持っていません。
セマフォなどのキューは、持っています阻塞机制
。タスクは、割り込みが発生するのを待つ必要があり、対応する処理が再度実行され、タスクは中断がセマフォのリリース後に発生した後に、タスクは、対応する処理を実行するためにウェイクアップされるまでセマフォ待つ、ブロッキング状態にすることができます。リリース(post
)セマフォ準備タスクで最も優先度の高いタスク、タスクはすぐに実行できる場合、タスクはすぐに、準備状態への変化を待つことになるとき、これはオペレーティングシステムです实时响应,实时处理
「」セマフォは、プロセスの効率を向上させることができるオペレーティングシステムで使用されます。
セマフォのデータ構造
セマフォ制御ブロック
TencentOS tiny
データ型であるセマフォセマフォによって制御ブロック操作k_sem_t
、セマフォ制御ブロック要素が複数存在するpend_obj_t
タイプpend_obj
及びk_sem_cnt_t
種類がcount
。しながら、pend_obj
オブジェクト指向継承と幾分同様に、いくつかのプロパティは、カーネルリソースの種類(例えば等セマフォ、キュー、ミューテックスなど、および待機リストが記載されていますlist
)。そしてcount
、それは(16ビットの符号なし整数である)単純な変数であり、セマフォの値を表します。
typedef struct k_sem_st {
pend_obj_t pend_obj;
k_sem_cnt_t count;
} k_sem_t;
セマフォに関連付けられたマクロ定義
tos_config.h
信号は、マクロ量TOS_CFG_SEM_EN
#define TOS_CFG_SEM_EN 1u
セマフォ達成
TencentOS tiny
唯一のコアコードで実装セマフォは、非常に単純である125
ラインは非常に少ないといえます。
セマフォを作成します。
システムにおける信号の量は、このようなリソースタイプ、ならびにその信号の大きさは、次に想像その待機リストとして各制御ブロックは、制御ブロック中の信号の量は、信号の全ての情報量が含まれている対応するセマフォを有します、自然は、ブロックが、それを初期化することであるセマフォセマフォのコントロールを作成することではないでしょうか?明らかにそれはそのようなものです。セマフォの量によってブロック制御信号の次の動作が操作されているので、情報がない場合、制御ブロック、それはうまく動作する方法〜
セマフォ関数を作成するtos_sem_create()
セマフォは、制御ブロックへのポインタである、2つの引数を指定して、*sem
他のセマフォの初期値であるinit_count
、非負の整数値は、しかし主に超えることができません65535
。
実際に呼び出しpend_object_init()
信号ブロックの量を制御する機能sem->pend_obj
のメンバ変数は、それがリソースタイプとして識別され、初期化されますPEND_TYPE_SEM
。次にsem->count
渡された信号の量の初期値にメンバ変数を設定しますinit_count
。
__API__ k_err_t tos_sem_create(k_sem_t *sem, k_sem_cnt_t init_count)
{
TOS_PTR_SANITY_CHECK(sem);
pend_object_init(&sem->pend_obj, PEND_TYPE_SEM);
sem->count = init_count;
return K_ERR_NONE;
}
セマフォを破壊します
セマフォデストラクタを直接破壊信号量の制御に応じてブロックされ、破壊後の全てのセマフォは、システムが必要であり、信号量が破棄されるとき、それはタスクリストが存在する待ち、クリアされ、そして再びセマフォを使用することはできませんこれらのタスクは、ウェイクアップ待って、タスクセマフォが破棄された通知されますPEND_STATE_DESTROY
。そして、最も優先度の高いタスクの実行に切り替えるには、タスクスケジューラを生成します。
TencentOS tiny
次のようにセマフォ破壊プロセスは、次のとおりです。
- コール
pend_is_nopending()
セマフォを待っているタスクがあるかどうかを判断する機能を - その場合は、呼び出す
pend_wakeup_all()
関数は、これらのタスクを覚ますと、セマフォが破壊された知らせるためにタスクを待ちます(つまり、待ち状態のタスク制御ブロックメンバ変数が設定されpend_state
ていますPEND_STATE_DESTROY
)。 - コール
pend_object_deinit()
最も重要なをクリアする機能セマフォ制御コンテンツブロックは、制御ブロックのリソースタイプが設定されているPEND_TYPE_NONE
ので、子供がセマフォを使用することはできません。 - タスクのスケジューリング
knl_sched()
注意:セマフォ制御ブロックRAMが行われた場合编译器静态分配
、セマフォが破壊されても、これはメモリを解放する方法はありません。もちろん、あなたはまた、メモリを割り当てるためにセマフォの動的メモリ制御ブロックを使用することができますが、破壊は、このメモリは、メモリリークを避けたい解放された後。
__API__ k_err_t tos_sem_destroy(k_sem_t *sem)
{
TOS_CPU_CPSR_ALLOC();
TOS_PTR_SANITY_CHECK(sem);
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
if (!pend_is_nopending(&sem->pend_obj)) {
pend_wakeup_all(&sem->pend_obj, PEND_STATE_DESTROY);
}
pend_object_deinit(&sem->pend_obj);
TOS_CPU_INT_ENABLE();
knl_sched();
return K_ERR_NONE;
}
セマフォを取得
tos_sem_pend()
関数は、セマフォを取得するために使用されたときにセマフォの有効時にセマフォを得るために仕事。タスクがセマフォを取得すると、セマフォ数マイナス1が利用可能になった、それが0である場合、セマフォを獲得するタスクは時間ブロッキング、ブロッキング状態になりtimeout
、ユーザによって指定し、指定した時刻に信号を得ることができません量はタイムアウト待ちタスクが自動的に準備状態に戻ります送信されます。
セマフォの手順を取得し、次のとおりです。
- 最初の着信パラメータを検出し、正しいです。
- ブロックの量を制御するための信号解析
count
メンバ変数はより大きく、0
0よりも大きいが、利用可能な信号の量は、存在することを示す、count
メンバ変数の値减1
成功した復帰後の取得タスクK_ERR_NONE
。 - 何セマフォユーザ指定の遮断時に見て、現在のタスクの取得をブロックすることができるが存在しない場合に
timeout
ブロックするかどうかがTOS_TIME_NOWAIT
ブロックされていない場合は、そのままリターンK_ERR_PEND_NOWAIT
エラーコード。 - スケジューラがロックされている場合
knl_is_sched_locked()
、あなたは操作のために待つことができないと、エラーコードを返しK_ERR_PEND_SCHED_LOCKED
、すべての後に、タスクを切り替える必要があり、スケジューラは、タスクを切り替えることはできませんロックされています。 - コール
pend_task_block()
機能タスクがブロックされ、この機能は、タスクリストから削除されようとし、実際に準備ができているk_rdyq.task_list_head[task_prio]
、と順番待ちリストに挿入されたobject->list
待機時間が永遠に待っていない場合、TOS_TIME_FOREVER
また、タスクリスト挿入時間、しかしk_tick_list
、時間をブロックしtimeout
、その後、タスクのスケジューリングknl_sched()
。 - それを行うためのプログラムがすると
pend_state2errno()
、それが表し任务等获取到信号量
、または等待发生了超时
それから呼び出し、pend_state2errno()
待ち状態のタスクについて取得する機能を実行するために、回復タスクにつながっているものを見ている、その結果がセマフォのタスクを取得し、呼び出し元に返されます。
注意:回復操作をブロックするのタスクからセマフォを取得した場合、必ずしも、それはタイムアウトがプログラムを書くときにセマフォ獲得の状態は、それがある場合にどのような決定する必要があり、発生している可能性がセマフォを取得するためにK_ERR_NONE
、その後それは成功を表し!
__API__ k_err_t tos_sem_pend(k_sem_t *sem, k_tick_t timeout)
{
TOS_CPU_CPSR_ALLOC();
TOS_PTR_SANITY_CHECK(sem);
TOS_IN_IRQ_CHECK();
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
if (sem->count > (k_sem_cnt_t)0u) {
--sem->count;
TOS_CPU_INT_ENABLE();
return K_ERR_NONE;
}
if (timeout == TOS_TIME_NOWAIT) { // no wait, return immediately
TOS_CPU_INT_ENABLE();
return K_ERR_PEND_NOWAIT;
}
if (knl_is_sched_locked()) {
TOS_CPU_INT_ENABLE();
return K_ERR_PEND_SCHED_LOCKED;
}
pend_task_block(k_curr_task, &sem->pend_obj, timeout);
TOS_CPU_INT_ENABLE();
knl_sched();
return pend_state2errno(k_curr_task->pend_state);
}
セマフォをリリース
タスクまたはサービス割り込みルーチンは、(ポスト)セマフォを解放セマフォの性質はのセマフォ制御ブロックで解放することができるcount
メンバ変数の値が加1
、有効な量を表す信号が、セマフォを待っている間にタスクがある場合、セマフォ制御ブロックcount
、目を覚ます目を覚ますとタスクの性質を待つのを待っているタスクがセマフォを取得するためのタスクを待つことであるため、メンバ変数の値は、のセマフォ制御ブロック変更されませんcount
にメンバ変数の値を减1
状回には、この、ブロック量制御信号count
メンバ変数の値が変更されません。
TencentOS tiny
あなただけのセマフォの取得を待っているタスクを作成するだけでなく、すべてのタスクがセマフォを取得するために待っていることができますすることができます。各APIに対応しているtos_sem_post()
とtos_sem_post_all()
。ちなみにポイント、tos_sem_post_all()
デザインパターンは、観察対象の変更は、すべてのオブザーバーは、それが変更されている知っているだろう、特に「西のデザインパターン」の本を見ると、実際に観測モードです。
TencentOS tiny
良い設計が簡単で低結合である場合には、これらの2つの呼び出しは、APIインターフェースは、本質的にされているsem_do_post()
セマフォを解放するように機能するが、によってopt
異なるパラメータ異なる処理方法を選択します。
でsem_do_post()
、ハンドラは次のようなアイデアの実行があり、非常に簡単です:
- ようにするために、最初に、セマフォがあるため、整数オーバーフローのオーバーフローしたかを決定は常に、常にセマフォを解放することができないだろう
count
メンバ変数の値加1
ならば、それは、どのようなオーバーフローを決定する必要があるsem->count
値が(k_sem_cnt_t)-1
、その後、継続することができない、オーバーフローしましたセマフォを解放し、エラーコードがK_ERR_SEM_OVERFLOWを返しました。 - コール
pend_is_nopending()
セマフォを待っているタスクがあるかどうかを判断するための機能を、そうでない場合は、その後count
のメンバ変数の値が加1
、リターンはK_ERR_NONE
この時点でタスクのスケジューリングを目覚めていないする必要がないため、リリースセマフォの成功を示し、直接返すことができます。 - セマフォを待っているタスクがある場合は、
count
メンバ変数の値は无需加1
、への直接呼び出しpend_wakeup
、対応するタスクが目を覚ますために、ウェイクタスクが基づいているopt
ウェイクアップのパラメータは、タスクを覚ますことができますまたはすべてのタスクを待っています。 - タスクのスケジューリングを行うために
knl_sched()
。
__API__ k_err_t tos_sem_post(k_sem_t *sem)
{
TOS_PTR_SANITY_CHECK(sem);
return sem_do_post(sem, OPT_POST_ONE);
}
__API__ k_err_t tos_sem_post_all(k_sem_t *sem)
{
TOS_PTR_SANITY_CHECK(sem);
return sem_do_post(sem, OPT_POST_ALL);
}
__STATIC__ k_err_t sem_do_post(k_sem_t *sem, opt_post_t opt)
{
TOS_CPU_CPSR_ALLOC();
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
if (sem->count == (k_sem_cnt_t)-1) {
TOS_CPU_INT_ENABLE();
return K_ERR_SEM_OVERFLOW;
}
if (pend_is_nopending(&sem->pend_obj)) {
++sem->count;
TOS_CPU_INT_ENABLE();
return K_ERR_NONE;
}
pend_wakeup(&sem->pend_obj, PEND_STATE_POST, opt);
TOS_CPU_INT_ENABLE();
knl_sched();
return K_ERR_NONE;
}
裁判官は理由についてsem->count
である(k_sem_cnt_t)-1
ことのオーバーフローを代表して?私はC言語で簡単な例を挙げてみましょう:
#include <stdio.h>
int main()
{
unsigned int a = ~0;
if(a == (unsigned int)0XFFFFFFFF)
{
printf("OK\n");
}
if(a == (unsigned int)-1)
{
printf("OK\n");
}
printf("unsigned int a = %d \n",a);
return 0;
}
输出:
OK
OK
unsigned int a = -1
概要
リーンと短いコード、明確な思考、強くお勧め深度調査〜
私はそれに焦点を当てるのが好き!
関連のコードは、バック公共数の取得「19」を返信することができます。
詳細については懸念「物事のIoT開発、」公共の番号を喜ばせます!