バックグラウンド
- ソフトウェアのデバッグ、多くのコードは記述されていません。デバッグなしで、問題がどこにあるか、特にRT_ASSERTアサーションを知ることができます。
- さらに多くの関数があります。RT_ASSERTアサーションが表示された後、rt_freeアサーションなど、何がうまくいかなかったのかをすぐに理解することは困難です。
- Keil MDK5 Debugを使用して、アサーションの真の位置をすばやくアサートし、ソフトウェアをデバッグするにはどうすればよいですか?
ケーススタディ
- 以前にRT-Threadメールボックスの使用をテストするためにBUGプログラムを作成しましたが、動的メモリのアプリケーションとリリースが使用されているため、rt_freeをアサートする必要があります。
- まず、問題を特定する必要があります。rt-threadrt_free関数に問題があるとは言えません。!誤った使用が原因である可能性があります。
- Keil MDK5はデバッグモードです。呼び出し元などの関数の呼び出し関係は、デバッグウィンドウ[呼び出しスタック]、呼び出しスタックウィンドウで確認できます。
- [つるをたどる]を通して、本当の呼び出し関数、つまり問題の場所を見つけてください。!
トラブルシューティング
- このルーチンの問題は、rt_free nullポインターが原因であるため、メモリの適用と解放の不適切なペア操作が原因である必要があります。
- すぐに問題が見つからなかったため、問題コードの場所にブレークポイントを設定し、2回目の実行中にrt_freeポインターに問題があるか、ワイルドポインターであることがわかりました。
- 引用:extern void list_mem(void);印刷に追加して、メモリがどんどん増えていることを確認してください!!(rt_freeリリースがたくさん!!)
- 失敗したコードの部分は次のとおりです。
struct mb_msg
{
rt_uint8_t *data_ptr;
rt_uint32_t data_size;
};
static void thread1_entry(void *param)
{
struct mb_msg *msg_recv_ptr1;
struct mb_msg *msg_send_ptr1;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg)); /* !!!! 申请内存的位置放错了!!!*/
while(1)
{
if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr1->data_ptr);
rt_free(msg_recv_ptr1);
rt_thread_mdelay(500);
msg_send_ptr1->data_size = sizeof(sbuf);
msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
}
}
}
- メモリが適用されていた場所が間違っていることが判明したため、この関数は初期化中に1回だけメモリに適用されました。使用されると、ワイルドポインタになります。
- 解決策:メモリに適用するコードをwhile(1)ループに入れ、各操作でメモリに適用します。!
static void thread1_entry(void *param)
{
struct mb_msg *msg_recv_ptr1;
struct mb_msg *msg_send_ptr1;
char sbuf[6] = {'T', 'a', 's', 'k', '1', '.'};
while(1)
{
if (rt_mb_recv(&t1_mb, (rt_ubase_t *)&msg_recv_ptr1, RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("thread 1:[recv=%s], print 1.\n", msg_recv_ptr1->data_ptr);
rt_thread_mdelay(10);
rt_free(msg_recv_ptr1->data_ptr);
list_mem();
rt_free(msg_recv_ptr1);
list_mem();
rt_thread_mdelay(500);
msg_send_ptr1 = (struct mb_msg *)rt_malloc(sizeof(struct mb_msg));
msg_send_ptr1->data_size = sizeof(sbuf);
msg_send_ptr1->data_ptr = (rt_uint8_t *)rt_malloc(msg_send_ptr1->data_size);
rt_memcpy(msg_send_ptr1->data_ptr, sbuf, sizeof(sbuf));
rt_kprintf("thread 1:[send=%s]\n", msg_send_ptr1->data_ptr);
rt_mb_send(&t2_mb, (rt_uint32_t)msg_send_ptr1);
}
}
}
総括する
- RT_ASSERTはまだ比較的使いやすく、正しいブレークポイントに注意を払い、デバッグし、非常に効率的です。
- 実際の問題を解決するために、より多くのデバッグ方法を要約します。