Return (large) unchange mxArray from MEX
이전 댓글 표시
Hi all ..
With a large array out to CPP / MEX, under certain conditions there will be no manipulation of the original data. Can someone please provide an example of how to properly return this original array in the most efficient manner?
Essentially plhs[0] = prhs[0] logically.
Many thanks, Mark
채택된 답변
추가 답변 (4개)
"plhs[0] = prhs[0]" is forbidden in MEX-programming, because re-using the inputs as outputs collides with the copy-on-write mechanism. Unfortunately the best (means documented and stable) method is to duplicate the array:
plhs[0] = mxDuplicateArray(prhs[0]);
And if it is your opinion, that this is not efficient for large array: Welcome to the team of MEX users, who ask TMW to document the methods for the creation of shared data copy. Please send an enhancement request to TMW.
You can try it with the undocumented mxCreateSharedDataCopy(). But a clean inplace processing would be much better.
[EDITED] James' explanation is correct and valuable. If you want the MEX to create an unchanged shared data copy of the inputs, plhs[0]=prhs[0] is valid. I've denied that, because this is a very rare need for a MEX function and I assumed, the contents of this variable must be changed inside the MEX. Then this can be observed:
// file: TestMex.c
#include "mex.h" // Must be called with a DOUBLE as input
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
plhs[0] = prhs[0]; // Ok until here
*mxGetPr(plhs[0]) = -1.0; // Don't do this
}
Compile it and run:
a = 1:4;
b = a; % Shared data copy inside Matlab
c = TestMex(b); % Modified shared data copy inside MEX
c % -1 2 3 4 as wanted
b % -1 2 3 4 !!!
a % -1 2 3 4 !!!
This means, that you plhs[0]=prhs[0] is valid, but modifications of the contents of plhs[0] are not and will destroy the integrity of the input values. Therefore performing this copy inside a MEX will not be useful for any real purpose.
What happens for:
format debug
a = 1:4;
a
a = TestMex(a)
format long g % clean up only
Now a is a shared data copy of itself. The Structure Address an pr are the same, but the increased reference counter might cause a memory leak. Unfortunately my trials to prove this have not been successful.
@Mark: I can unaccept my answer on demand.
댓글 수: 7
James Tursa
2013년 5월 27일
편집: James Tursa
2013년 5월 27일
This is not true. plhs[0] = prhs[0] is prefectly OK. See my answer for the explanation.
Jan
2013년 5월 28일
James is correct and my expression "forbidden" has to be taken with care. See [EDITED].
James Tursa
2013년 5월 28일
There shouldn't be any problem with your a = TestMex(a) scenario. Doing that is no different from doing this:
a = 1:4;
b = a; % b is a shared data copy of a
a = b; % setting a equal to a shared data copy of itself
Assigning a variable to a shared data copy of itself can happen anywhere in m-code, not just in mex routines. There shouldn't be any worry about incorrect reference counts.
Jan
2013년 5월 30일
@James: Thanks, let me think twice, before I ask the next question about how Matlab detects, when the last instance of shared data is deleted, such that the memory can be freed.
James Tursa
2013년 5월 30일
@Jan: The CrossLink field in the mxArray structure contains the next mxArray in the linked list of shared data copy variables (for later versions of MATLAB the list is a double linked list). When this field is NULL, there are no shared data copies around. The reference count also has to be checked (for reference copies existing in cell and struct arrays). When the CrossLink is NULL and the reference count is 0, the data memory can be free'd when the variable is destroyed. This applies to most variables. For variables derived from the handle class, the rules are different (they are shared data copies without a CrossLink address).
Jan
2013년 5월 30일
@James: And now I assume, that the CrossLink and the ReferenceCounts are set correctly, when a is replaced by a shared data copy of itself coming from a MEX-function, which ignores the CONST qualifier of the input. I trust TMW, that the mechanisms are stable. But I know also, that using undocmumented methods means a certain risk of evil bugs and incompatibilities.
James Tursa
2013년 6월 3일
편집: James Tursa
2013년 6월 3일
@Jan: I pretty much am in agreement with you. The fact that the following statement
plhs[0] = (mxArray *) prhs[0];
overrides the const attribute of prhs[0], and the fact that the shared-data-copy method of returning plhs[ ] variables is not documented, is a bit unsettling as a programmer. However, I put it in the same category of using any of the other undocumented functions/features. E.g., I routinely use mxCreateSharedDataCopy because it has proven to be reliable and it works across multiple platforms and versions. No guarantee it will work in the future, but that doesn't stop me from using it ... the advantage is just too great not to in many cases.
댓글 수: 4
James Tursa
2013년 5월 27일
plhs[0] = prhs[0] is perfectly OK. See my answer for the explanation.
This thread is a little old, but I hope you gurus are still monitoring it. Q: what about creating a variable that points somewhere in the middle of prhs[0]'s data? will this break matlab's memory management system? Specifically, consider a large matrix, and wanting to split it into 2 smaller parts for processing separately:
i
>> % in matlab:
>> clear
>> % mem usage is 884 MB
>> x = rand(1000000,100);
>> % mem usage is now 1.61 GB
>> y = x(:,51:100);
>> % mem usage is now 2.01 GB
Unfortunately it appears that matlab duplicated the second portion of x, although there's no real need to do so, since I'm not modifying the original data. It seems like I should be able to create a zero-sized matrix in mexFunction, resize it, and point to the middle of the array, and return it without duplicating the data
% in matlab:
>> y = my_subarray(x,51); % get sub-array of x starting at row 51
and something like this inside mexFunction my_subarray(...):
// in C++:
double *p = msGetPtr(prhs[0]);
mxArray *B;
B = mxCreateDoubleMatrix(0, 0, mxREAL);
mxSetM(1000000);
mxSetN(100);
mxSetData(B, p+50*1000000);
plhs[0] = B;
But your examples above only deal with pointing to the entire original matrix. In my case, my need for this would not modify the sub-array, but it's not clear to me if this would break matlab's modify-on-write memory management...
James Tursa
2017년 10월 30일
No, you cannot do this in a mex routine. In the first place, the following line will bomb MATLAB with an assertion fault since the p+50*1000000 address will not match anything that the MATLAB Memory Manager generated:
mxSetData(B, p+50*1000000);
Even if you could set this address into the mxArray data pointer (using older versions of MATLAB or via a mxArray hack), when MATLAB subsequently destroys this mxArray downstream it will cause a seg fault because that address will mess up the memory manager.
The only thing you could do is hack into the mxArray header itself to set the data pointer directly (avoiding the assertion fault that the official API functions would generate), use this mxArray ONLY inside the mex routine, then manually detach that data pointer inside the mex routine prior to destroying the mxArray. Under no circumstances could this mxArray, which is in an invalid state when the mid memory block data pointer is present, be returned back to MATLAB as one of the plhs[ ] variables. All that being said, creating and using this partial mxArray is NOT ADVISED, is VERY TRICKY to implement, and risks bombing MATLAB.
E.g., see this FEX submission by Bruno Luong:
James Tursa
2018년 1월 25일
Another option that was just posted to the FEX for getting shared data copies of contiguous sub-sections of an existing variable:
댓글 수: 3
James Tursa
2013년 5월 30일
For the record, I am not concerned about the "points". No need to change anything on my account.
@Mark: As long as my answer had no (non-trivial) comments, I could delete and resubmit it for un-accepting. But now I do not want to loose the discussion with James in the comments. I ask the admins for clearing the flag.
@James: I think, it is important, that for this non-trivial topic the answer with the highest value can be recognized by the readers. And your reputation can in fact not be increased by any kind of "points".
Mark
2013년 6월 2일
댓글 수: 2
James Tursa
2013년 5월 30일
I would suggest the following to make the code robust against C/C++ implementations:
#ifdef __cplusplus
extern "C"
{
#endif
mxArray *mxCreateSharedDataCopy(const mxArray *pr);
// and any other prototypes for undocumented API functions you are using
#ifdef __cplusplus
}
#endif
And for the assignment itself do an explicit cast to override the const:
plhs[0] = (mxArray *) prhs[0];
Mark
2013년 5월 31일
카테고리
도움말 센터 및 File Exchange에서 Write C Functions Callable from MATLAB (MEX Files)에 대해 자세히 알아보기
제품
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!