Main Content

MATLAB コードからの再呼び出し可能な C コードの生成

このチュートリアルについて

学習目的

このチュートリアルでは以下の方法について説明します。

  • 永続データやグローバル データを使用しない MATLAB® コードから、再呼び出し可能なコードを生成する。

  • MATLAB コードから C コードを自動生成する。

  • コマンド ラインで関数の入力プロパティを定義する。

  • コード生成プロパティを指定する。

  • MATLAB コードの表示とデバッグに使用できるコード生成レポートを生成する。

メモ

この例は Windows® 上のみで動作します。

必要条件

この例を実行するには、次の製品をインストールします。

  • MATLAB

  • MATLAB Coder™

  • C コンパイラ

    MATLAB Coder では、サポートされているインストール済みのコンパイラが検索されて使用されます。サポートされているコンパイラの最新のリストは、MathWorks® Web サイトのサポートされるコンパイラを参照してください。

    mex -setup を使用して既定のコンパイラを変更できます。既定のコンパイラの変更を参照してください。

必要なファイル

タイプ名前説明
関数のコードmatrix_exp.mテイラー級数を使用して入力行列の行列指数を計算し、計算結果の出力を返す MATLAB 関数
C の main 関数main.c 再呼び出し可能なコードを呼び出す。

例について

この例は Microsoft® Windows オペレーティング システム専用のライブラリが必要なため、Windows プラットフォーム上でのみ実行できます。永続データやグローバル データを使用しないシンプルなマルチスレッドの例です。2 つのスレッドによって、異なる入力データセットをもつ MATLAB 関数 matrix_exp が呼び出されます。

現在の作業フォルダーに、次のコードを含むファイル matrix_exp.m を作成します。

function Y = matrix_exp(X) %#codegen
    %
    % The function matrix_exp computes matrix exponential of 
    % the input matrix using Taylor series and returns the 
    % computed output.
    E = zeros(size(X));
    F = eye(size(X));
    k = 1;
    while norm(E+F-E,1) > 0
        E = E + F;
        F = X*F/k;
        k = k+1;
    end
    Y = E;

再利用可能で再呼び出し可能なコードを生成すると、MATLAB Coder では次の動的な割り当てがサポートされます。

  • スタックには大きすぎる関数変数

  • 永続変数

  • グローバル変数

MATLAB Coder によってヘッダー ファイル primary_function_name_types.h が生成され、生成コードを使用する際にはこのヘッダー ファイルを含めなければなりません。このヘッダー ファイルには、以下の構造体が含まれます。

  • primary_function_nameStackData

    ユーザーが割り当てたメモリを含みます。次の方法により、構造体を使用する関数に対し、最初のパラメーターとしてその構造体へのポインターを渡します。

    • 直接使用する (関数は構造体内のフィールドを使用する)

    • 間接的に使用する (関数は呼び出した関数に構造体を渡す)

    アルゴリズムが永続データまたはグローバル データを使用する場合は、primary_function_nameStackData 構造体には primary_function_namePersistentData 構造体へのポインターも含まれています。このポインターが含まれている場合、呼び出し元の各関数には 1 つのパラメーターを渡すだけで済みます。

  • primary_function_namePersistentData

    アルゴリズムで永続変数またはグローバル変数を使用する場合は、MATLAB Coder によってこの変数のために個別の構造体が提供されます。メモリの割り当て構造体にはこの永続データ構造体へのポインターが含まれます。永続変数とグローバル変数のために独立した構造体があるので、この変数に対して 1 度メモリを割り当てるだけで、すべてのスレッドで共有できるようになります。スレッド間のやり取りがない場合は、これらの変数に対してスレッドごとにメモリを割り当てることができます。

C の main 関数の記述

再呼び出し可能なコードを呼び出すには、次の条件を満たす main 関数を記述します。

  • 生成されたヘッダー ファイル matrix_exp.h を含む。このファイルは生成されたヘッダー ファイル matrix_exp_types.h を含みます。

  • 各スレッドに対し、スタック データのためのメモリを割り当てる。

  • ハウスキーピング関数 matrix_exp_initialize を呼び出す。詳細については、生成コードの展開を参照してください。

  • matrix_exp を呼び出す。

  • matrix_exp_terminate を呼び出す。

  • スタック データ メモリのために容量を解放します。

現在の作業フォルダーに、次のコードを含むファイル main.c を作成します。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "matrix_exp.h"
#include "matrix_exp_initialize.h"
#include "matrix_exp_terminate.h"
#include "rtwtypes.h"
#define NUMELEMENTS (160*160)

typedef struct {
    real_T in[NUMELEMENTS];
    real_T out[NUMELEMENTS];
    matrix_expStackData* spillData;
} IODATA;

/* The thread_function calls the matrix_exp function written in MATLAB */
DWORD WINAPI thread_function(PVOID dummyPtr) {
    IODATA *myIOData = (IODATA*)dummyPtr;
    matrix_exp_initialize();
    matrix_exp(myIOData->spillData, myIOData->in, myIOData->out);
    matrix_exp_terminate();
    return 0;
}

void main() {
  HANDLE thread1, thread2;
  IODATA data1;
  IODATA data2;
  int32_T i;
  
  /*Initializing data for passing to the 2 threads*/
  matrix_expStackData* sd1 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData));
  matrix_expStackData* sd2 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData));
  
  data1.spillData = sd1;
  data2.spillData = sd2;
  
  for (i=0;i<NUMELEMENTS;i++) {
      data1.in[i] = 1;
      data1.out[i] = 0;
      data2.in[i] = 1.1;
      data2.out[i] = 0;
  }
  
  /*Initializing the 2 threads and passing data to the thread functions*/
  printf("Starting thread 1...\n");
  thread1 = CreateThread(NULL , 0, thread_function, (PVOID) &data1, 0, NULL);
  if (thread1 == NULL){
	     perror( "Thread 1 creation failed.");
		   exit(EXIT_FAILURE);
  	}

  printf("Starting thread 2...\n");
  thread2 = CreateThread(NULL, 0, thread_function, (PVOID) &data2, 0, NULL);
  if (thread2 == NULL){
      perror( "Thread 2 creation failed.");
      exit(EXIT_FAILURE);
  }
  
  /*Wait for both the threads to finish execution*/
  if (WaitForSingleObject(thread1, INFINITE) != WAIT_OBJECT_0){
	     perror( "Thread 1 join failed.");
		  exit(EXIT_FAILURE);
  	}
   
  if (WaitForSingleObject(thread2, INFINITE) != WAIT_OBJECT_0){
		  perror( "Thread 2 join failed.");
		  exit(EXIT_FAILURE);
	  }  
  
  free(sd1);
  free(sd2);
  
  printf("Finished Execution!\n");
  exit(EXIT_SUCCESS);
  }

ビルド パラメーターの構成

再呼び出し可能なコードの生成は、コード生成構成オブジェクトを使用して有効にします。

  1. 構成オブジェクトを作成します。

    cfg = coder.config('exe');

  2. 再呼び出し可能なコードの生成を有効にします。

    cfg.MultiInstanceCode = true;

C コードの生成

次のオプションを使用して、C コードを生成する関数 codegen を呼び出します。

  • -config: コード生成構成オブジェクト cfg を渡します。

  • main.c: このファイルをコンパイルに含めます。

  • -report: コード生成レポートを作成します。

  • -args: 例のデータを使用して入力引数のクラス、サイズおよび複素数を指定します。

codegen -config cfg main.c -report matrix_exp.m -args ones(160,160)

codegen は、現在のフォルダーに C の実行可能ファイル matrix_exp.exe を生成し、/codegen/exe/matrix_exp サブフォルダーに C コードを生成します。レポートの生成を選択したため、codegen によってレポートへのリンクが提供されます。

生成された C コードの表示

codegen によって、グローバル構造体 matrix_expStackData を定義するヘッダー ファイル matrix_exp_types.h が生成されます。この構造体には、大きすぎてスタックに収まらないローカル変数が含まれています。

このヘッダー ファイルを表示するには、次の手順に従います。

  1. [レポートの表示] リンクをクリックして、コード生成レポートを開きます。

  2. 生成ファイルのリストで、matrix_exp_types.h をクリックします。

/*
 * matrix_exp_types.h
 *
 * Code generation for function 'matrix_exp'
 *
 */

#ifndef __MATRIX_EXP_TYPES_H__
#define __MATRIX_EXP_TYPES_H__

/* Include files */
#include "rtwtypes.h"

/* Type Definitions */
#ifndef typedef_matrix_expStackData
#define typedef_matrix_expStackData

typedef struct {
  struct {
    double F[25600];
    double Y[25600];
    double X[25600];
  } f0;
} matrix_expStackData;

#endif                                 /*typedef_matrix_expStackData*/
#endif

/* End of code generation (matrix_exp_types.h) */

コードの実行

この例が Windows プラットフォーム上で実行されることを確認して、コードを呼び出します。

% This example can only be run on Windows platforms
if ~ispc
 error('This example requires Windows-specific libraries and can only be run on Windows.');
end
system('matrix_exp.exe')

実行可能ファイルが実行され、完了したことがレポートされます。

覚えておきたい重要なポイント

  • 次の条件を満たす main 関数を作成します。

    • 生成されたヘッダー ファイル primary_function_name_types.h を含む。このファイルは primary_function_nameStackData グローバル構造体を定義します。この構造体には、大きすぎてスタックに収まらないローカル変数が含まれています。

    • 各スレッドに対し、スタック データのためのメモリを割り当てる。

    • primary_function_name_initialize を呼び出す。

    • primary_function_name を呼び出す。

    • primary_function_name_terminate を呼び出す。

    • スタック データ メモリを解放します。

  • -config オプションを使用して、コード生成構成オブジェクトを関数 codegen に渡します。

  • コマンド ラインで -args オプションを使用して、入力パラメーターを指定します。

  • -report オプションを使用して、コード生成レポートを作成します。

詳細

目的参照先

生成されるコードの API についてさらに学習する

生成された再利用可能なコードの API

永続データやグローバル データをもたない再呼び出し可能なコードを UNIX® 上で呼び出す

永続データまたはグローバル データを使用しない再呼び出し可能なコードの呼び出し (UNIX のみ)

永続データをもつ再呼び出し可能なコードを Windows 上で呼び出す

再呼び出し可能なコードの呼び出し — 永続データを使用したマルチスレッド (Windows のみ)

永続データをもつ再呼び出し可能なコードを UNIX 上で呼び出す

再呼び出し可能なコードの呼び出し — 永続データを使用したマルチスレッド (UNIX のみ)