コンテンツにスキップ

システム操作 - スレッド/プロセス操作

1.1. マルチスレッドの概要

プロセスとスレッドの概念は、オペレーティングシステム(OS)と一般的なマイコンの最大の違いです。マルチタスクシステムではシステムリソースを分割し、異なるタスクを独立して実行させることができます。また、マクロな視点で見ると、複数のアプリケーションが同時に実行されているように見えます(例:ウェブブラウザを見ながら音楽を再生するなど)。これがプロセスとスレッドを導入する重要なポイントです。

1.2. クイックスタート

1.2.1 開発環境の準備

このドキュメントを初めて読む場合は、『スタートガイド/開発環境の準備/Easy-Eaiコンパイル環境の準備と更新』を一読し、その手順に従ってコンパイル環境の構築を行ってください。

PC上のUbuntuシステムで runスクリプトを実行し、EASY-EAIコンパイル環境に入ります。詳細は以下の通りです。

Terminal window
cd ~/develop_environment
./run.sh 2204

1.2.2 ソースコードのダウンロードとサンプルのコンパイル

EASY-EAIコンパイル環境下で、ソースコードリポジトリを管理するディレクトリを作成します。

Terminal window
cd /opt
mkdir EASY-EAI-Toolkit
cd EASY-EAI-Toolkit
  • ダウンロードリンク: Demos.zip 上記のリンクから Demos.zip 圧縮ファイルをダウンロードし、仮想マシンの /opt/EASY-EAI-Toolkit ディレクトリにアップロードして解凍します。 対応するサンプルのディレクトリに移動し、コンパイル操作を実行します。具体的なコマンドは以下の通りです。
Terminal window
cd EASY-EAI-Toolkit-1126B/Demos/common-system_opt/
./build.sh

💡 注意 : 依存ライブラリがボード上に配置されているため、クロスコンパイル中は必ず/mnt のマウントを維持してください。

1.2.2 ソースコードのダウンロードとサンプルのコンパイル 図27

1.2.2 ソースコードのダウンロードとサンプルのコンパイル 図27

1.2.3 サンプルの実行

シリアルデバッグまたはSSHデバッグを通じてボードのバックグラウンドに入り、サンプルが配置されている場所に移動します。以下の通りです。

Terminal window
cd /userdata/Demo/common-system_opt

1.2.3 サンプルの実行 図28

1.2.3 サンプルの実行 図28

サンプルの実行コマンドは以下の通りです。

Terminal window
./test-thread-opt

1.2.4 実行結果

実行結果は以下のようになります。

1.2.4 実行結果 図29

1.2.4 実行結果 図29

APIの詳細な説明、およびAPIの呼び出し(本サンプルのソースコード)については、以下の説明を参照してください。

1.3. スレッド操作APIの説明

1.3.1 インクルード/参照方法

EASY EAI api ライブラリは、本リポジトリの easyeai-apiディレクトリにあります。お客様がローカルプロジェクトで EASY EAI apiライブラリを直接呼び出せるように、プロジェクト内でリンクする必要があるライブラリやヘッダーファイル等を以下にリストアップしています。

説明CMakeでの記述Makefileでの記述
api.cmake${common_root}/system_opt/api.cmake無し
ヘッダーファイルディレクトリ${SYSTEM_OPT_INCLUDE_DIRS}-I ../../easyeai-api/common/system_opt
ソースファイルディレクトリ${SYSTEM_OPT_SOURCE_DIRS}../../easyeai-api/common/system_opt
ライブラリファイルディレクトリ無し無し
ライブラリリンクパラメータ${SYSTEM_OPT_LIBS}無し

APIソースコードのパスはEASY-EAI-Toolkit-1126B/easyeai-api/common/system_opt/です。ユーザーはソースコードを通じてインターフェースの実装を確認でき、ソースコードを直接変更することも可能です。

1.3.2 スレッドタスクのプロトタイプ

スレッドタスクのプロトタイプは以下の通りです。スレッドタスクはプログラム実行の最小単位であり、以下のように定義されます。

typedef void \*(\*ThreadEntryPtrType)(void \*);

1.3.3 スレッド作成関数

スレッド作成関数のプロトタイプは以下の通りです。

int32_t CreateNormalThread(ThreadEntryPtrType entry, void \*para, pthread_t \*pid);

具体的な説明は以下の通りです。

関数名:CreateNormalThread()詳細
ヘッダーファイルeasyeai-api/common/system_opt/system_opt.h
入力パラメータentry:スレッドの本体となる実行関数
para:スレッドに渡す引数(共有変数として使用)
pid:新規作成される pthread_t
型オブジェクトへのポインタ
戻り値作成失敗時は -1 を返す
作成成功時は 0 を返す
注意事項pid
変数はシステムが割り当てるスレッドIDを格納するために使用されます。NULLを渡すとプログラムが異常終了する原因になります。

1.3.4 シェルコマンドの実行 - system() の呼び出し

シェルコマンドを実行する関数のプロトタイプは以下の通りです。

int32_t exec_cmd_by_system(const char \*cmd);

この関数は system() を呼び出すことで実装されています。具体的な説明は以下の通りです。

関数名:exec_cmd_by_system()詳細
ヘッダーファイルeasyeai-api/common/system_opt/system_opt.h
入力パラメータcmd:シェルコマンド
戻り値forkに失敗した場合、system() 関数は -1
を返します。execが成功し、コマンドが正常に終了した場合、コマンドが exit
または return で返した値を返します。
注意事項1. エラー時により有用な情報を得るため、system() 実行後の errno
値を監視することを推奨します。
2.
非同期(ノンブロッキング)実行の注意点:コマンドをバックグラウンドへ移行させるため
&
を付与し、同時に出力をリダイレクトしてください。そうしないとブロッキング実行になります。

1.3.5 シェルコマンドの実行 - popen() の呼び出し

シェルコマンドを実行する関数のプロトタイプは以下の通りです。

int32_t exec_cmd_by_popen(const char \*cmd, char \*result);

この関数は popen() を呼び出すことで実装されており、実行結果を取得することができます。具体的な説明は以下の通りです。

関数名:exec_cmd_by_popen()詳細
ヘッダーファイルeasyeai-api/common/system_opt/system_opt.h
入力パラメータcmd:シェルコマンド
result:シェルコマンド実行後、返された結果がこのメモリ領域に格納されます
戻り値呼び出し失敗時は -1 を返す
呼び出し成功時は 0 を返す(result に正常に書き込まれた状態)
注意事項コマンドの実行に失敗した場合、子プロセスはエラーメッセージを標準エラー出力にプリントするため、親プロセスはそれを取得できません。
エラーメッセージをキャプチャする必要がある場合は、子プロセスのエラー出力を標準出力にリダイレクト(2>&1)してください。これにより、親プロセスでエラー情報を取得できるようになります。
例:exec_cmd_by_popen(“ls 2>&1”, result);

1.4. スレッド操作APIの使用例

スレッド操作APIの使用例となるコードのパスは以下の通りです:

EASY-EAI-Toolkit-1126B/Demos/common-system_opt/test-thread-opt.c スレッド作成のケースは、「スレッド実行本体」と「スレッド作成操作」の2つの部分で構成されています。

スレッド実行本体は以下の通りです。

void *testThreadBody(void *arg)
{
int *share_para = (int *)arg;
while(1)
{
printf("[tesThread] --- share_para = %d\n", *share_para);
if(*share_para > 10){
printf("[tesThread] --- exit\n");
break;
}
sleep(1);
}
pthread_exit(NULL);
}

スレッド作成操作は以下の通りです。pId変数はプロセス(スレッド)IDの格納に使用され、share_para変数は入力パラメータを保持します。

pthread_t pId;
int share_para = 0;
if(0 == CreateNormalThread(testThreadBody, &share_para,
&pId))
{
while(1){
printf("[mainThread] --- \n");
share_para++;
sleep(1);
}
}