Calling C++ mex in loop crashes Matlab

Goal: to interface with a device via a dll to collect and plot continuous data.
Problem: loadlibrary does not work since one of the exported functions take a function pointer as argument. So I wrote a mex file in c++ (compiled with VS2019). This works in the sense that all exported functions can be called from Matlab and return the expected data. However, when the read data function is called repeatedly in a loop, Matlab becomes unresponsive and then exits without any error message. Increasing the pause in each loop iteration or decreasing the sample rate of the device, makes this less likely to happen.
When initializing the device a pointer to a global function has to be provided, which will be called by the device repeatedly to write data. I copy the data to a global vector in this function and then copy this to plhs[0] in the read data function that is called from Matlab.
I suspected that the problem was caused by dataBuffer being read and written to simultaneously, so I added the isWriting/Reading flags (below). Still, the data in DataBuffer is not always evenly divisible by the nuber of channels, even though the device always writes an equal number of samples per channel for each channel, so it seems I still read the vector while being filled in in the global function.
I also tried debugging with Visual Studio, and it seems Matlab hits an Access violation when this happens, but I was not able to track down where this occurs.
The relevant code in the mex file (I trimmed out most of it):
#define N_CHANNELS 16
// Global functions:
void ReadDataFromDevice(int samples, channels, float *data);
// Global variables:
std::vector <float> dataBuffer; //dataBuffer.reserve(N_CHANNELS * samplerate) is called when recording starts
int isWriting = 0;
int isReading = 0;
class device_mex {
public:
protected:
};
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
char cmd[64];
device_mex* device_mex_instance;
mxGetString(prhs[0], cmd, sizeof(cmd));
// Read - read from and clear data buffer
if (!strcmp("read", cmd)){
if (!isWriting & !(dataBuffer.size() % N_CHANNELS)){
isReading = 1;
plhs[0] = mxCreateNumericMatrix(dataBuffer.size(),1,mxSINGLE_CLASS,mxREAL);
memcpy((float*) mxGetData(plhs[0]),dataBuffer.data(),dataBuffer.size()*sizeof(float));
dataBuffer.clear();
isReading = 0;
}else{
plhs[0] = mxCreateNumericMatrix(0,0,mxSINGLE_CLASS,mxREAL);
}
return;
}
}
void ProcessDataFromDevice(int samples, int channels, float *data){
if (!isReading){
isWriting = 1;
for(int i=0;i<(samples*channels);i++){
dataBuffer.push_back(data[i]);
}
isWriting = 0;
}
}
...which gets called through a Matlab classdef:
function [data] = readDevice(this)
data = [];
if ~this.isRecording
error('Could not read data buffer. Device is not recording.');
elseif strcmp(this.deviceStatus,'IS_OK')
data = device_mex('read');
if ~isempty(data)
data = reshape(data,this.nChannels,length(data)/this.nChannels)';
end
else
error('Device not ready: %s',this.deviceStatus);
end
end
...in a while loop:
while isvalid(figureHandle)
pause(.1);
d = readDevice(device);
if ~isempty(d)
buffer = [buffer;d(:,dig1Channel)];
end
pline.YData=buffer(end-buflen+1:end);
drawnow;
end

 Accepted Answer

Jan
Jan on 11 Apr 2021
There is a time delay between the check of !isWriting and setting isReading = 1. This is a racing condition. Use a thread-safe semaphore instead.

1 Comment

Thank you for a quick and helpful reply, Jan! I will look into this, but it sounds like exactly what is needed here and I learned something new.

Sign in to comment.

More Answers (0)

Categories

Tags

Asked:

on 11 Apr 2021

Commented:

on 12 Apr 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!