前回の記事では、EventQueueについてThe EventQueue API Tutorialでメモリの分断が起こる可能性があるというところまで読んでみました。今回は、メモリの分断についてさらに考えます。
題材について
この記事で題材として取り上げたのは、The EventQueue APIというTutorialです。
メモリの分断に起因する不具合(Failure due to fragmentation)
The following example would fail because of fragmentation:
以下の例では、メモリの分断によって不具合を発生します。
EventQueue queue(4*sizeof(int)); // 4 words of storage
queue.call(func); // requires 1 word of storage
queue.call(func); // requires 1 word of storage
queue.call(func); // requires 1 word of storage
queue.call(func); // requires 1 word of storage
// 0 words of storage remain
queue.dispatch(); // free all pending events
// all memory is free again (4 words) and in one-word chunks
queue.call(func, 1, 2, 3); // requires 4 words of storage, so allocation fails
Four words of storage are free but only for allocations of one word or less.
4ワードのメモリ領域が解放されますが、メモリが分断されたままなので、1ワード以下の領域しか確保できません。
The solution to this failure is to increase the size of your EventQueue.
この不具合の解決策は、EventQueueのサイズを大きくすることです。
Having the proper sized EventQueue prevents you from running out of space for events in the future.
適切なサイズのEventQueueを取り扱えば、イベントのためのメモリが将来枯渇するのを防ぐことができます。
と、コードが出てきましたが、このコードも変ですので書き直しました。
#include "mbed.h"
void func(int a, ...) {
printf("func(%d)\r\n", a);
}
int main() {
EventQueue queue(4 * EVENTS_EVENT_SIZE); // four events of storage
printf("Start\r\n");
printf("call(1)=%d\r\n", queue.call(func, 1)); // requires 2 words of storage
printf("call(2)=%d\r\n", queue.call(func, 2)); // requires 2 words of storage
printf("call(3)=%d\r\n", queue.call(func, 3)); // requires 2 words of storage
printf("call(4)=%d\r\n", queue.call(func, 4)); // requires 2 words of storage
// after this we have 2 words of storage left
queue.dispatch(0); // free all pending events
// all memory is free again (4 words) and in one-word chunks
printf("call(5)=%d\r\n", queue.call(func, 5, 5, 5)); // fails
queue.dispatch(0); // free all pending events
}
実行結果は、以下の通りです。
Start
call(1)=256
call(2)=300
call(3)=344
call(4)=388
func(1)
func(2)
func(3)
func(4)
call(5)=0
EventQueueには、4イベント分のメモリ領域を確保しました。そこに2ワードしか必要としないイベントを4本入れてやると、メモリが分断されて、すべてのイベントが2ワードしか受け入れられなくなります。queue.dispatch()
でイベントを実行してイベントを開放しても状況は変わりません。大きなメモリ領域を必要とする5番目のイベントは、キューに入れることができません。
イベントに関するさらなる情報(More about events)
This is only a small part of how event queues work in Mbed OS.
この文書は、Mbed OSでイベントキューがどのように動作するかについてのほんの一部にしか過ぎません。
The
EventQueue
,Event
andUserAllocatedEvent
classes in thembed-events
library offer a lot of features that this document does not cover, including calling functions with arguments, queueing functions to be called after a delay or queueing functions to be called periodically.
mbed-events
ライブラリのEventQueue
、Event
、UserAllocatedEvent
の各クラスは、多くの機能を提供しています。そこには、この文書で述べられていない、引数を伴った関数の呼び出し、遅れて呼び出される関数をキューに入れること、周期的に呼び出される関数をキューに入れること、が含まれています。
The README of the
mbed-events
library shows more ways to use events and event queues.
mbed-events
ライブラリのREADMEにイベントとイベントキューのさらなる用途が書かれています。
To see the implementation of the events library, review the equeue library.
イベントライブラリの実装について知りたいときには、equeueライブラリを参照してください。
次回は、スタティックなEventQueueについて考えます。
追記 (2020-02-08)
このコード例も、githubにIssueを出した後、修正されました。
// event size in words: 9 + callback_size + arguments_size (where 9 is internal space for event data)
void func0();
void func3(int, int, int);
EventQueue queue(4*(9+1)*sizeof(int)); // 40 words of storage
queue.call(func0); // requires 10 word of storage (9+1)
queue.call(func0); // requires 10 word of storage (9+1)
queue.call(func0); // requires 10 word of storage (9+1)
queue.call(func0); // requires 10 word of storage (9+1)
// 0 words of storage remain
queue.dispatch(); // free all pending events
// all memory is free again (40 words) and in 10-word chunks
queue.call(func3, 1, 2, 3); // requires 13 words of storage (9+4), so allocation fails
が、これもqueue.dispatch()
の引数が無く、queue.call()
の返り値も確認されていないので、何が起こっているかわからないはずです。
関連サイト
Mbed OSのページ
EventQueueのTutorial
Mbed対応Cypress製品のページ
関連記事
EventQueueを使ってみたよ (1)
EventQueueを使ってみたよ (2)
EventQueueを使ってみたよ (3)
EventQueueを使ってみたよ (4)
EventQueueを使ってみたよ (5)
EventQueueを使ってみたよ (6)
EventQueueを使ってみたよ (7)
EventQueueを使ってみたよ (8)
EventQueueを使ってみたよ (9)