Call Reentrant Code — Multithreaded with Persistent Data (Windows Only)
This example requires libraries that are specific to the Microsoft® Windows® operating
system and, therefore, runs only on Windows platforms. It is
a multithreaded example that uses persistent data. Two threads call
the MATLAB® function matrix_exp with different
sets of input data.
MATLAB Code for This Example
function [Y,numTimes] = matrix_exp(X) %#codegen
%
% The function matrix_exp computes matrix exponential
% of the input matrix using Taylor series and returns
% the computed output. It also returns the number of
% times this function has been called.
%
persistent count;
if isempty(count)
count = 0;
end
count = count+1;
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 ;
numTimes = count; |
Provide a Main Function
To call reentrant code that uses persistent data, provide a main function
that:
Includes the header file
matrix_exp.h.For each thread, allocates memory for stack data.
Allocates memory for persistent data, once per root process if threads share data, and once per thread otherwise.
Calls the
matrix_exp_initializehousekeeping function. For more information, see Deploy Generated Code.Calls
matrix_exp.Calls
matrix_exp_terminate.Frees the memory used for stack and persistent data.
For this example, main.c contains:
#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];
real_T numTimes;
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(myIOData->spillData);
matrix_exp(myIOData->spillData, myIOData->in, myIOData->out, &myIOData->numTimes);
printf("Number of times function matrix_exp is called is %g\n",myIOData->numTimes);
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_expPersistentData* pd1 = (matrix_expPersistentData*)calloc(1,sizeof(matrix_expPersistentData));
matrix_expPersistentData* pd2 = (matrix_expPersistentData*)calloc(1,sizeof(matrix_expPersistentData));
matrix_expStackData* sd1 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData));
matrix_expStackData* sd2 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData));
sd1->pd = pd1;
sd2->pd = pd2;
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;
}
data1.numTimes = 0;
data2.numTimes = 0;
/*Initializing the 2 threads and passing required 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);
free(pd1);
free(pd2);
printf("Finished Execution!\n");
exit(EXIT_SUCCESS);
} |
Generate Reentrant C Code
Run the following script at the MATLAB command prompt to generate code.
% 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
% Setting the options for the Config object
% Create a code gen configuration object
cfg = coder.config('exe');
% Enable reentrant code generation
cfg.MultiInstanceCode = true;
% Compiling
codegen -config cfg main.c -report matrix_exp.m -args ones(160,160)
|
This script:
Generates an error message if the example is not running on a Windows platform.
Creates a code generation configuration object for generation of an executable.
Enables the
MultiInstanceCodeoption to generate reusable, reentrant code.Invokes
codegenwith the following options:-configto pass in the code generation configuration objectcfg.main.cto include this file in the compilation.-reportto create a code generation report.-argsto specify an example input with class, size, and complexity.
Examine the Generated Code
codegen generates a header file matrix_exp_types.h,
that defines:
The
matrix_expStackDataglobal structure that contains local variables that are too large to fit on the stack and a pointer to thematrix_expPersistentDataglobal structure.The
matrix_expPersistentDataglobal structure that contains persistent data.
/*
* 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_expPersistentData
#define typedef_matrix_expPersistentData
typedef struct {
double count;
} matrix_expPersistentData;
#endif /*typedef_matrix_expPersistentData*/
#ifndef typedef_matrix_expStackData
#define typedef_matrix_expStackData
typedef struct {
struct {
double F[25600];
double Y[25600];
double X[25600];
} f0;
matrix_expPersistentData *pd;
} matrix_expStackData;
#endif /*typedef_matrix_expStackData*/
#endif
/* End of code generation (matrix_exp_types.h) */
|
Run the Code
Call the code using the command:
system('matrix_exp.exe')See Also
Control Stack Space Usage | Stack Allocation and Performance