文書化されていませんが、MEX API 関数mxCreateSharedDataCopy
は、の共有データ コピーを作成するためのソリューションとしてMathWorks によって提供されましたが、現在は明らかに否定されていmxArray
ます。MathWorks は、ソリューションの例も提供していますmxsharedcopy.c
。
削除された MathWorks ソリューション (1-6NU359) で説明されているように、この関数を使用してmxArray
ヘッダーを複製できます。plhs[0] = prhs[0];
ただし、実行と実行の違いplhs[0] = mxCreateSharedDataCopy(prhs[0]);
は、最初のバージョンはmxArray*
(a ポインター) をコピーするだけであり、新しいコンテナーを作成しないことですmxArray
(少なくとも、mexFunction
返されて MATLAB が魔法のように機能するまで)、両方でデータの参照カウントをインクリメントします。mxArray
秒。
なぜこれが問題になるのでしょうか? から戻る前にを使用plhs[0] = prhs[0];
し、それ以上変更しない場合は、すべて問題なく、MATLAB のおかげで共有データ コピーが作成されます。ただし、上記の割り当ての後にMEX 関数で変更すると、同じデータ バッファーを参照するため、変更も見られます。一方、( を使用して) 共有コピーを明示的に生成すると、2 つの異なるオブジェクトがあり、1 つの配列のデータを変更するとコピー操作がトリガーされ、2 つの完全に独立した配列が作成されます。また、直接代入は、場合によってはセグメンテーション違反を引き起こす可能性があります。plhs[0]
mexFunction
plhs[0]
prhs[0]
mxCreateSharedDataCopy
mxArray
変更された MathWorks の例
mxsharedcopy.c
上記で参照されている MathWorks ソリューションから変更された を使用した例から始めます。mxCreateSharedDataCopy
最初の重要なステップは、関数のプロトタイプを提供することです。
/* Add this declaration because it does not exist in the "mex.h" header */
extern mxArray *mxCreateSharedDataCopy(const mxArray *pr);
コメントにあるように、これは にないmex.h
ため、自分で宣言する必要があります。
の次の部分では、次の方法でmxsharedcopy.c
新しい を作成します。mxArray
経由のディープコピーmxDuplicateArray
:
copy1 = mxDuplicateArray(prhs[0]);
経由の共有コピーmxCreateSharedDataCopy
:
copy2 = mxCreateSharedDataCopy(copy1);
mxArray*
私が追加したの直接コピー:
copy0 = prhs[0]; // OK, but don't modify copy0 inside mexFunction!
次に、それぞれの最初の値のデータ バッファー ( pr
)のアドレスを出力します。変更されたformxArray
の出力は次のとおりです。mxsharedcopy(x)
x=ones(1e3);
prhs[0] = 72145590, mxGetPr = 18F90060, value = 1.000000
copy0 = 72145590, mxGetPr = 18F90060, value = 1.000000
copy1 = 721BF120, mxGetPr = 19740060, value = 1.000000
copy2 = 721BD4B0, mxGetPr = 19740060, value = 1.000000
どうしたの:
- 予想どおり、 を比較する
prhs[0]
とcopy0
、同じ への別のポインターを除いて、新しいものは何も作成されていませんmxArray
。
- と を比較する
prhs[0]
と、で新しいアドレスが作成され、 データが で新しいバッファにコピーされてcopy1
いることに注意してください。mxDuplicateArray
mxArray
721BF120
19740060
copy2
は とは異なるアドレス ( mxArray*
) を持っていますcopy1
。つまり、異なる変数が指している同じものだけでなく、アドレスで同じデータを共有しています。mxArray
19740060
質問は次のようになります:またはplhs[0]
のいずれcopy0
かcopy2
(単純なポインターのコピー または から) を返すのは安全ですか、それとも実際にデータをコピーするmxCreateSharedDataCopy
を使用する必要がありますか? それがまだ有効であることを破棄して検証することで、それが機能するmxDuplicateArray
ことを示すことができます。mxCreateSharedDataCopy
copy1
copy2
mxDestroyArray(copy1);
copy2val0 = *mxGetPr(copy2); % no crash!
入力への共有データ コピーの適用
質問に戻ります。これを MathWorks の例よりさらに一歩進めて、入力の共有データ コピーを返します。ただ行う:
if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
息を止めて!
>> format debug
>> x=ones(1,2)
x =
Structure address = 9aff820 % mxArray*
m = 1
n = 2
pr = 2bcc8500 % double*
pi = 0
1 1
>> xDup = mxsharedcopy(x)
xDup =
Structure address = 9afe2b0 % mxArray* (different)
m = 1
n = 2
pr = 2bcc8500 % double* (same)
pi = 0
1 1
>> clear x
>> xDup % hold your breath!
xDup =
Structure address = 9afe2b0
m = 1
n = 2
pr = 2bcc8500 % double* (still same!)
pi = 0
1 1
一時的な入力(なしformat debug
)の場合:
>> tempDup = mxsharedcopy(2*ones(1e3));
>> tempDup(1)
ans =
2
興味深いことに、なしでmxCreateSharedDataCopy
(つまり、 だけでplhs[0] = prhs[0];
) テストすると、MATLAB はクラッシュしませんが、出力変数は決して実現しません。
>> tempDup = mxsharedcopy(2*ones(1e3)) % no semi-colon
>> whos tempDup
>> tempDup(1)
Undefined function 'tempDup' for input arguments of type 'double'.
R2013b、Windows、64 ビット。
mxsharedcopy.cpp (変更された C++ バージョン):
#include "mex.h"
/* Add this declaration because it does not exist in the "mex.h" header */
extern "C" mxArray *mxCreateSharedDataCopy(const mxArray *pr);
bool mxUnshareArray(const mxArray *pr, const bool noDeepCopy); // true if not successful
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
mxArray *copy1(NULL), *copy2(NULL), *copy0(NULL);
//(void) plhs; /* Unused parameter */
/* Check for proper number of input and output arguments */
if (nrhs != 1)
mexErrMsgTxt("One input argument required.");
if (nlhs > 1)
mexErrMsgTxt("Too many output arguments.");
copy0 = const_cast<mxArray*>(prhs[0]); // ADDED
/* First make a regular deep copy of the input array */
copy1 = mxDuplicateArray(prhs[0]);
/* Then make a shared copy of the new array */
copy2 = mxCreateSharedDataCopy(copy1);
/* Print some information about the arrays */
// mexPrintf("Created shared data copy, and regular deep copy\n");
mexPrintf("prhs[0] = %X, mxGetPr = %X, value = %lf\n",prhs[0],mxGetPr(prhs[0]),*mxGetPr(prhs[0]));
mexPrintf("copy0 = %X, mxGetPr = %X, value = %lf\n",copy0,mxGetPr(copy0),*mxGetPr(copy0));
mexPrintf("copy1 = %X, mxGetPr = %X, value = %lf\n",copy1,mxGetPr(copy1),*mxGetPr(copy1));
mexPrintf("copy2 = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
/* TEST: Destroy the first copy */
//mxDestroyArray(copy1);
//copy1 = NULL;
//mexPrintf("\nFreed copy1\n");
/* RESULT: copy2 will still be valid */
//mexPrintf("copy2 = %X, mxGetPr = %X, value = %lf\n",copy2,mxGetPr(copy2),*mxGetPr(copy2));
if (nlhs>0) plhs[0] = mxCreateSharedDataCopy(prhs[0]);
//if (nlhs>0) plhs[0] = const_cast<mxArray*>(prhs[0]);
}