Main Content

Managing 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')

See Also

Related Topics