Manage External Resources from MEX Functions
MEX functions that connect to external resources like sockets, sensors, files, and databases need to manage these resources. Because you implement C++ MEX functions as classes, you can define constructor and destructor functions to manage these resources and variables that persist across repeated calls to the MEX function.
When you call a MEX function, MATLAB® creates an instance of the MexFunction
class. This
object persists for the MATLAB session or until you clear the object with the clear
mex
command. Repeated calls to the MEX function can process incoming
data and release resources when finished.
Reading a Text File
This MEX function opens a text file and reads one word each time you call the
function. The MexFunction
class that implements the MEX function
defines a constructor and a destructor to open and close the file. Each word read is
stored in an std::unordered_map
to determine the number of times
that word occurs in the file.
Constructor
The MexFunction
constructor performs these steps:
Call
mexLock
to prevent clearing of the MEX function from memory.Get the full path to the text file from MATLAB using eval and getVariable.
Open the text file to the
std::ifstream
input stream.
Destructor
The class destructor closes the file.
Function Call Operator operator()
Each call to the MEX function reads a word from the text file and adds it to
the unordered map, or just increments the word count for that word if it exists
in the map. The MEX function displays the current word and its count in the
MATLAB command window using a std::ostringstream
output stream. To unlock the MEX function, pass an argument (such as
'unlock'
) to the function.
Display On MATLAB
The displayOnMATLAB
member function uses feval to call the MATLAB
fprintf
function with the
string written to the output stream.
Code Listing
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <unordered_map>
#include <fstream>
using matlab::mex::ArgumentList;
using namespace matlab::data;
class MexFunction : public matlab::mex::Function {
// Input stream to read words from file
std::ifstream inFile;
// Unordered map to keep track of word count
std::unordered_map<std::string, int> wordCount;
// Pointer to MATLAB engine
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
// Factory to create MATLAB data arrays
ArrayFactory factory;
public:
MexFunction() {
mexLock();
matlabPtr->eval(u"fname = fullfile(matlabroot,'extern','examples','cpp_mex','data','sonnets.txt');");
matlab::data::CharArray fileName = matlabPtr->getVariable(u"fname");
inFile.open(fileName.toAscii());
if (!inFile.is_open()) {
std::ostringstream stream;
stream << "Failed to open sonnets.txt" << std::endl;
displayOnMATLAB(stream);
}
}
~MexFunction() {
if (inFile.is_open())
inFile.close();
}
void operator()(ArgumentList outputs, ArgumentList inputs) {
if (inFile.is_open() && !inFile.eof()) {
std::string word;
inFile >> word;
wordCount[word]++;
std::ostringstream stream;
stream << "Read : " << "\"" << word << "\""
<< ", current count: " << wordCount[word] << std::endl;
displayOnMATLAB(stream);
}
if (!inputs.empty() || !inFile.is_open()) {
mexUnlock();
}
}
void displayOnMATLAB(const std::ostringstream& stream){
matlabPtr->feval(u"fprintf", 0,
std::vector<Array>({ factory.createScalar(stream.str()) }));
}
};
Build and Run sonnetWordCount.cpp
Open the source code file, sonnetWordCount.cpp
, in the editor and use
the mex
command to compile the MEX
function.
mex sonnetWordCount.cpp
Call the MEX function repeatedly to count word usage.
>> sonnetWordCount Read : "THE", current count: 1 >> sonnetWordCount Read : "SONNETS", current count: 1 >> sonnetWordCount Read : "by", current count: 1 >> sonnetWordCount Read : "William", current count: 1 >> sonnetWordCount Read : "Shakespeare", current count: 1 >> sonnetWordCount('unlock')