入門
私たちはしばしば、プログラミングで使用される金属裸可能性があるflag
イベントが発生するかをマークするために使用されるこの変数を、そしてそれは、あなたにもあり、複数のイベントを待つのであれば、その後、ループ内でこれらのマーカーが発生したかどうかを判断するif((xxx_flag)&&(xxx_flag))
。このような判断を行うこと。もちろん、学生が取る賢明であろう場合に、このような最初の桁として行う兆候は、可変示すイベントを、第二の表す2つのイベントが起こっているときに、入射し、それと判定された値を判断するために、数ありますどのイベントが発生しました。flag
某些位
A
B
flag&0x03
しかし、どのように我々は、オペレーティング・システムに達成しますか?
イベント
オペレーティングシステムでは、事件
カーネルリソース、主のために、データ送信機能!任务与任务间、中断与任务间
同步
不提供
そして、の使用信号量
同期が若干異なります。それは、イベントの多くは、多くの同期を達成することができます。これは、複数のイベントが発生したため、タスクが待つことができます:いずれかのウェイクアップイベント処理タスクいずれかのイベント中に、また、いくつかのイベントウェイクアップイベント処理タスクの後に発生したことができます。同様に、複数のイベントを同期するために、複数のタスクが存在することができます。
各イベント・グループは、最小限必要RAM
イベントフラグを保持するための空間を事件(控制块)
含んでいる旗标
こと、旗标
各ビットが「を表し事件
、」フラグに格納されているk_event_flag_t
変数(名前の種類flag
、理解するのが簡単フラグ事件标记变量
)、変数は、それぞれイベント、タスクを表し、イベント制御ブロックで定義されている“逻辑与”
か、“逻辑或”
イベントが発生したときに1つ以上の関連イベントと、タスクが起床されるであろう。
イベント「OR」であり
独立型同步
、タスクが起こされるのを待ちイベントにはいくつかのイベントのいずれかを参照して、;イベント「論理」で
关联型同步
待機しているすべてのタスクでのイベントの数を参照して、都
唯一の目覚めが発生すること。
イベントタスクの通信は、タスク間の同期を達成するために使用することができる実施メカニズムが、データなしの送信イベントです。マルチタスク環境、タスク、多くの場合、割り込みの間に操作を同期する必要があるが、タスク、中断して、タスク間の同期とタスクの形成した場合で待っているタスクを伝えます。
イベント无排队性
かつて一度だけセットと同等の同じイベントタスク(タスクがまだ行く読む時間を持っていない場合)、より多くのを設定します。
さらにイベントは、多くの同期動作の多くを、多くを提供することができます。
一对多
同期モデル:トリガー複数のイベントを待っているタスクは、このような状況がより一般的です。多对多
同期モデル:トリガー複数のイベントを待っている複数のタスク、タスクがイベントをトリガするイベントを達成し、ビットを設定することにより、操作を待つことができます。
イベントデータ構造
イベント制御ブロック
TencentOS tiny
データ・タイプであるイベント制御ブロックによって操作イベントはk_event_t
、イベント制御ブロックは、複数の要素から構成されています。
pend_obj
いくつかのプロパティ、オブジェクト指向継承に幾分類似、カーネルリソースの種類(例えばミューテックスキューミューテックスなど、および待機リストが記載されていますlist
)。flag
フラグ、32ビット変数、各イベント制御ブロック32のみイベントを識別できるように!
typedef struct k_event_st {
pend_obj_t pend_obj;
k_event_flag_t flag;
} k_event_t;
イベントに関連付けられたタスク制御ブロックデータ構造
typedef struct k_task_st {
···
k_opt_t opt_event_pend; /**< 等待事件的的操作类型:TOS_OPT_EVENT_PEND_ANY 、 TOS_OPT_EVENT_PEND_ALL */
k_event_flag_t flag_expect; /**< 期待发生的事件 */
k_event_flag_t *flag_match; /**< 等待到的事件(匹配的事件) */
···
} k_task_t;
イベントに関連するマクロ定義
tos_config.h
マクロ定義イベントスイッチが配置されていますTOS_CFG_EVENT_EN
#define TOS_CFG_EVENT_EN 1u
tos_event.h
中間、いくつかのマクロ定義があるが、(イベントを操作するために使用されていますopt选项
)。
// if we are pending an event, for any flag we expect is set is ok, this flag should be passed to tos_event_pend
#define TOS_OPT_EVENT_PEND_ANY (k_opt_t)0x0001
// if we are pending an event, must all the flag we expect is set is ok, this flag should be passed to tos_event_pend
#define TOS_OPT_EVENT_PEND_ALL (k_opt_t)0x0002
#define TOS_OPT_EVENT_PEND_CLR (k_opt_t)0x0004
TOS_OPT_EVENT_PEND_ANY
:タスクは、任意のイベント、「OR」を待っています!TOS_OPT_EVENT_PEND_ALL
:タスクはすべてのイベント、すなわち「AND」を待っています!TOS_OPT_EVENT_PEND_CLR
:保留中のイベントフラグをクリアするには、あってもよいTOS_OPT_EVENT_PEND_ANY
、TOS_OPT_EVENT_PEND_ALL
(によって混合“|”
演算子)。
データ構造列挙のタイプ、イベントを送信するための操作オプションがあるほかに、他のビット(すなわち、他のイベントの影響をカバーしている)イベントを送信し、元のフラグに保つことができるイベントフラグをクリアすることができ他のビット(なしカバーは、他のイベントに影響を与えません)。
typedef enum opt_event_post_en {
OPT_EVENT_POST_KEP,
OPT_EVENT_POST_CLR,
} opt_event_post_t;
イベントを作成します。
システムは、各イベントに対応するイベント制御ブロックを有し、イベント制御ブロックは、例えば、そのイベントを作成し、想像その待機リスト、そのリソース・タイプ、およびそのイベントフラグ値としてイベントに関するすべての情報が含まれていこれは、イベント制御ブロックの本質は、それを初期化するということではないでしょうか?明らかにそれはそのようなものです。、イベント制御ブロックにより、イベントのその後の動作が動作するための制御ブロック情報がない場合、どのようにそれがうまく動作することができます〜
関数はイベントで作成しtos_event_create()
たイベント制御ブロックへのポインタを渡して、*event
イベントに加えて、あなたは初期値を指定することができますinit_flag
。
イベントが実際に呼び出して作成しpend_object_init()
たイベント制御ブロックに機能をevent->pend_obj
メンバ変数が初期化され、それがリソースタイプとして識別されますPEND_TYPE_EVENT
。次いで、event->flag
メンバ変数は、イベントフラグの初期値をマークするように設定されていますinit_flag
。
__API__ k_err_t tos_event_create(k_event_t *event, k_event_flag_t init_flag)
{
TOS_PTR_SANITY_CHECK(event);
pend_object_init(&event->pend_obj, PEND_TYPE_EVENT);
event->flag = init_flag;
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
ので、子供はこの事件を使用することはできません。 event->flag
デフォルト値に回復メンバ変数0
。- タスクのスケジューリング
knl_sched()
注意:イベントは制御ブロックRAMによって決定された場合编译器静态分配
、そのイベントが破壊されても、これはメモリを解放する方法はありません。もちろん、あなたもイベントのためにメモリを割り当てる動的メモリ制御ブロックを使用することができますが、破壊は、このメモリは、メモリリークを避けたい解放された後。
__API__ k_err_t tos_event_destroy(k_event_t *event)
{
TOS_CPU_CPSR_ALLOC();
TOS_PTR_SANITY_CHECK(event);
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&event->pend_obj, PEND_TYPE_EVENT)) {
return K_ERR_OBJ_INVALID;
}
#endif
TOS_CPU_INT_DISABLE();
if (!pend_is_nopending(&event->pend_obj)) {
pend_wakeup_all(&event->pend_obj, PEND_STATE_DESTROY);
}
pend_object_deinit(&event->pend_obj);
event->flag = (k_event_flag_t)0u;
TOS_CPU_INT_ENABLE();
knl_sched();
return K_ERR_NONE;
}
イベントを待っています
tos_event_pend()
関数は、この関数を使用してイベントを取得するために使用され、あなたが知ることができる事件旗标
何位
で置1
発生した場合、そのタスクはイベントを待つために指定することができます“逻辑与”、“逻辑或”
待っている操作(opt_pend选项
)。
そして、この機能は実装して等待超时
メカニズムを、そしてイベントを待っているタスクが発生した場合にのみ、タスクがイベントを待つことができます。イベントが発生していない場合、イベントが時間ブロッキング、ブロッキング状態になるため、タスクが待機timeout
イベントが発生していない場合、この時点で、ユーザによって指定さを、タスクは、イベントが起こるのを待ってブロックされたままであろう。標準は、対応するイベントフラグフラグ他のタスクを設定するか、または待機中にサービス・ルーチンを中断すると、タスクは自動的に準備状態に状態をブロックすることによって。タスクの待機時間は、イベントが発生していない場合でも、指定されたブロッキング時間を超えた場合、タスクは自動的に準備完了状態にブロッキング状態から転送されます。このように非常に効果的にリアルタイム・オペレーティング・システムを反映しています。
タスクがイベントを取得するときは、イベントアクションをクリアすることを選択できます。
イベント割り込み操作が実行されているのコンテキストで許可されていません待って!
イベントを待っている間に、次のとおりです。
- 最初の着信パラメータを検出し、正しいです。、メモ
opt_pend
オプションが存在している必要がありTOS_OPT_EVENT_PEND_ALL
、またはTOS_OPT_EVENT_PEND_ANY
(一方、両者が存在することができ互斥
)。 - コール
event_is_match()
(つまり、タスクはイベントとイベント制御ブロックフラグかどうかを待っているイベントが発生したかを決定するための機能を待つかどうか匹配
)。 - で
event_is_match()
オプションを待っているに基づく関数opt_pend
(いずれかのイベントを待つことであるTOS_OPT_EVENT_PEND_ANY
)、または(すべてのイベントを待つTOS_OPT_EVENT_PEND_ANY
)一致が返された場合、一致するかどうかを判断するためK_TRUE
、それ以外のリターンをK_FALSE
することで、イベントを待っている間に、flag_match
変数を返す(マッチが発生しています) 。そして、すべてのイベントが発生した場合にだけ、すべてのオプションのための待ち時間が一致するとみなされます。(event & flag_expect) == flag_expect)
イベントを待つ任意のオプションでは、発生したイベントが一致すると見なされています:(event & flag_expect)
。 - イベントが発生した場合、それは現在のタスクの取得をブロックすることができない、ユーザが指定した遮断時間を見て
timeout
遮断するか否かTOS_TIME_NOWAIT
ブロックされていない場合は、そのままリターンK_ERR_PEND_NOWAIT
エラーコード。 - スケジューラがロックされている場合
knl_is_sched_locked()
、あなたは操作のために待つことができないと、エラーコードを返しK_ERR_PEND_SCHED_LOCKED
、すべての後に、タスクを切り替える必要があり、スケジューラは、タスクを切り替えることはできませんロックされています。 - 待つことが予想イベントを設定するために、そのタスクについて設定されたイベントについてのタスク制御ブロック変数
k_curr_task->flag_expect
、イベントを一致させるタスクk_curr_task->flag_match
、及びイベントタスクオプションを待ちますk_curr_task->opt_event_pend
。 - コール
pend_task_block()
機能タスクがブロックされ、この機能は、タスクリストから削除されようとし、実際に準備ができているk_rdyq.task_list_head[task_prio]
、と順番待ちリストに挿入されたobject->list
待機時間が永遠に待っていない場合、TOS_TIME_FOREVER
また、タスクリスト挿入時間、しかしk_tick_list
、時間をブロックしtimeout
、その後、タスクのスケジューリングknl_sched()
。 - プログラムがダウンして続けることができたとき、それは意味
任务等待到事件
場合、または等待发生了超时
タスクがイベントを待機する必要はありませんし、タスク制御ブロックの内容がクリアされ、この時間は、待機中のタスク必要なイベントクリアしk_curr_task->flag_expect
、タスクに一致するイベントk_curr_task->flag_match
、およびタスク待ちをオプションのイベントはk_curr_task->opt_event_pend
また、呼び出し中に、pend_state2errno()
タスクの待ち状態について取得する機能を実行するためのリカバリタスクにつながるような状況の種類を見て、呼び出し元の関数がイベントタスクを待ちに結果が返されます。
注意:障害物からのイベントを待っているタスクが動作を再開する場合は、イベントが発生するまで必ずしも待つ、タイムアウトがあるかもしれませんが発生したことがある場合は、そのプログラムを書くときには、どのようなイベントを決定するために状態を待つ必要がありK_ERR_NONE
、その後取り出し成功!
コードは以下の通りであります:
__STATIC__ int event_is_match(k_event_flag_t event, k_event_flag_t flag_expect, k_event_flag_t *flag_match, k_opt_t opt_pend)
{
if (opt_pend & TOS_OPT_EVENT_PEND_ALL) {
if ((event & flag_expect) == flag_expect) {
*flag_match = flag_expect;
return K_TRUE;
}
} else if (opt_pend & TOS_OPT_EVENT_PEND_ANY) {
if (event & flag_expect) {
*flag_match = event & flag_expect;
return K_TRUE;
}
}
return K_FALSE;
}
__API__ k_err_t tos_event_pend(k_event_t *event, k_event_flag_t flag_expect, k_event_flag_t *flag_match, k_tick_t timeout, k_opt_t opt_pend)
{
TOS_CPU_CPSR_ALLOC();
TOS_PTR_SANITY_CHECK(event);
TOS_PTR_SANITY_CHECK(flag_match);
TOS_IN_IRQ_CHECK();
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&event->pend_obj, PEND_TYPE_EVENT)) {
return K_ERR_OBJ_INVALID;
}
#endif
if (!(opt_pend & TOS_OPT_EVENT_PEND_ALL) && !(opt_pend & TOS_OPT_EVENT_PEND_ANY)) {
return K_ERR_EVENT_PEND_OPT_INVALID;
}
if ((opt_pend & TOS_OPT_EVENT_PEND_ALL) && (opt_pend & TOS_OPT_EVENT_PEND_ANY)) {
return K_ERR_EVENT_PEND_OPT_INVALID;
}
TOS_CPU_INT_DISABLE();
if (event_is_match(event->flag, flag_expect, flag_match, opt_pend)) {
if (opt_pend & TOS_OPT_EVENT_PEND_CLR) { // destroy the bridge after get across the river
event->flag = (k_event_flag_t)0u;
}
TOS_CPU_INT_ENABLE();
return K_ERR_NONE;
}
if (timeout == TOS_TIME_NOWAIT) {
TOS_CPU_INT_ENABLE();
return K_ERR_PEND_NOWAIT;
}
if (knl_is_sched_locked()) {
TOS_CPU_INT_ENABLE();
return K_ERR_PEND_SCHED_LOCKED;
}
k_curr_task->flag_expect = flag_expect;
k_curr_task->flag_match = flag_match;
k_curr_task->opt_event_pend = opt_pend;
pend_task_block(k_curr_task, &event->pend_obj, timeout);
TOS_CPU_INT_ENABLE();
knl_sched();
k_curr_task->flag_expect = (k_event_flag_t)0u;
k_curr_task->flag_match = (k_event_flag_t *)K_NULL;
k_curr_task->opt_event_pend = (k_opt_t)0u;
return pend_state2errno(k_curr_task->pend_state);
}
イベントを送信
TencentOS tiny
送信イベントは、すなわち、二つの機能を提供しますtos_event_post()
とtos_event_post_keep()
、二つの機能は、本質的に同じ関数が呼び出されているevent_do_post()
唯一のオプションは異なりますが、イベントを送信した動作を実現するために、使用tos_event_post()
機能に影響を与える可能性があり、指定されたイベントが上書きされます他の発生したイベント、およびtos_event_post_keep()
機能は、実際に、後者はより一般的に使用され、他のイベントの位置は変更されません同時イベントを維持することができます。
この関数は、イベントフラグの指定された位置に発生したイベントを書き込むために使用され、対応するビットが設定されている場合、タスクを復元する可能性が高いイベント待ち、この時間は、イベント待機リストを横断するイベントオブジェクトを待機する必要がありますタスクがあるかどうかを判断するために期望的事件
、現在と事件旗标
がある場合、値が一致し、その後、タスクを覚まします。
簡単に言えば、1にイベントフラグの独自の定義を設定して、このイベントを待っているタスクがあるかどうかを確認することです、はい、それは目を覚ますでしょう。
TencentOS tiny
デザインの良い場所は簡単で、低カップリングには、インタフェースのAPIの両方の性質に求めているevent_do_post()
イベントの発生に機能しますが、によってopt_post
異なるパラメータ異なるアプローチを選択しました。
でevent_do_post()
、ハンドラは次のようなアイデアの実行があり、非常に簡単です:
- まず、イベントのどのような方法を決定する
opt_post
ことがあれば、OPT_EVENT_POST_KEP
使用又は操作される“|”
イベントフラグ、または直接割り当てに書き込まれます。 - 使用する
TOS_LIST_FOR_EACH_SAFE
ことで、待機リストに待機するようにイベントオブジェクトを横断するイベントをevent_is_match()
タスクがあるかどうかを判断する機能を期望的事件
電流で事件旗标
値が一致呼び出す場合、pend_task_wakeup()
機能ウェイク対応するタスクを。 - 対応するイベントをクリアするために割り当てられたタスクを待っているのをきっかけ場合は、そのイベントのフラグ値をクリアします。
- 最後に、タスクのスケジューリング
knl_sched()
。
__STATIC__ k_err_t event_do_post(k_event_t *event, k_event_flag_t flag, opt_event_post_t opt_post)
{
TOS_CPU_CPSR_ALLOC();
k_task_t *task;
k_list_t *curr, *next;
#if TOS_CFG_OBJECT_VERIFY_EN > 0u
if (!pend_object_verify(&event->pend_obj, PEND_TYPE_EVENT)) {
return K_ERR_OBJ_INVALID;
}
#endif
if (opt_post == OPT_EVENT_POST_KEP) {
event->flag |= flag;
} else {
event->flag = flag;
}
TOS_CPU_INT_DISABLE();
TOS_LIST_FOR_EACH_SAFE(curr, next, &event->pend_obj.list) {
task = TOS_LIST_ENTRY(curr, k_task_t, pend_list);
if (event_is_match(event->flag, task->flag_expect, task->flag_match, task->opt_event_pend)) {
pend_task_wakeup(TOS_LIST_ENTRY(curr, k_task_t, pend_list), PEND_STATE_POST);
// if anyone pending the event has set the TOS_OPT_EVENT_PEND_CLR, then no wakeup for the others pendig for the event.
if (task->opt_event_pend & TOS_OPT_EVENT_PEND_CLR) {
event->flag = (k_event_flag_t)0u;
break;
}
}
}
TOS_CPU_INT_ENABLE();
knl_sched();
return K_ERR_NONE;
}
__API__ k_err_t tos_event_post(k_event_t *event, k_event_flag_t flag)
{
TOS_PTR_SANITY_CHECK(event);
return event_do_post(event, flag, OPT_EVENT_POST_CLR);
}
__API__ k_err_t tos_event_post_keep(k_event_t *event, k_event_flag_t flag)
{
TOS_PTR_SANITY_CHECK(event);
return event_do_post(event, flag, OPT_EVENT_POST_KEP);
}
私はそれに焦点を当てるのが好き!
関連のコードは、バック公共数の取得「19」を返信することができます。
詳細については懸念「物事のIoT開発、」公共の番号を喜ばせます!