从调用 MEX 的函数返回后 Matlab 崩溃
Matlab crash after returning from function that calls MEX
我正在创建一个 MEX,以使用 A* 算法找到两个节点之间的路径。代码按预期工作,检索到正确的结果,一切似乎都很好,但是当我从调用 MEX 的方法中 return 时,Matlab 只是自行关闭。
据我所知,有时当用户试图创建一个变量的副本时,Matlab 会创建一个指向相同内存地址的指针(即 A = 3;B = A,然后 A 和 B 指向相同的内存地址,即使 Matlab 将它们显示为 2 个自变量)我使用了一个老技巧,即直接对变量的副本执行操作,即使它很愚蠢,Matlab 也会认为这两个变量不再相同并且将创建它的副本(即 A = 3;B = A;B = B+0,现在 A 和 B 存储为不同的独立变量)。
因此,我发现解决此问题的唯一方法是在函数 getWP 中执行如下所示的操作:
function testAStarC()
% load the map of the area
load('epsp0_2_nav.mat');
% Set the initial node
initNode = '16x21';
% Set the target node
finalNode = '-15x54';
% Select Heuristic
heuristic = 'Manhattan';
% Create a target location (targetX, targetY, targetAngle)
targetCoords = [-15*110 54*110 0.15];
% Function that hosts the call to the MEX
wp = getWP(map, initNode, finalNode, targetCoords, heuristic);
disp('If you remove the line cellNodes{keyID}.x = cellNodes{keyID}.x; from getWP ...
I wont reach this line');
disp(['Route with ',num2str(length(wp)),' wp found']);
disp('done');
function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
% HashMap containing the nodes (this is a Java hashmap)
nodesHash = map.navMap.nodes.nodes;
keys = nodesHash.keys();
numNodes = length(keys);
cellNodes = cell(1,numNodes);
% Parse the nodes from the HashMap to Cells as the MEX seems to be
% unable to read directly from the Java HashMap
for keyID=1:numNodes
cellNodes{keyID} = nodesHash(keys{keyID});
%---------------------------------------------------------
% WITHOUTH THIS MATLAB CRASHES WHEN RETURNING FROM GETWP
%---------------------------------------------------------
% We need this to force Matlab to create a new copy of the content,
% otherwise will send a pointer aiming to the HashMap and crash when
% returning from getWP.
cellNodes{keyID}.x = cellNodes{keyID}.x;
end
waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);
disp('I am not crashing here if you remove cellNodes{keyID}.x = cellNodes{keyID}.x');
我的第一个想法是我在 MEX 中对“cellNodes”做错了什么,这导致 Matlab 崩溃,但我没有直接使用输入参数执行任何操作。这是节点 class:
的构造函数
Node.cpp
Node::Node(mxArray *cellElement)
{
double *xIn;
double *yIn;
char strIn[15];
double *posXIn;
double *posYIn;
double *weightIn;
double *tempVal;
size_t numCellElms;
mxArray *cellElement2;
numCellElms = mxGetNumberOfFields(cellElement);
size_t size;
for (int cellItem = 0; cellItem < numCellElms; cellItem++)
{
cellElement2 = mxGetCell(cellElement,cellItem);
if (cellItem == 0)
{
xIn = mxGetPr(cellElement2);
memcpy(tempVal,xIn,sizeof(double));
gridX = int(*tempVal);
}
if (cellItem == 1)
{
yIn = mxGetPr(cellElement2);
memcpy(tempVal,yIn,sizeof(double));
gridY = int(*tempVal);
}
if (cellItem >= 2 && cellItem < 10)
{
mwSize buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
if (buflen <= 1)
{
connections[cellItem-2][0] = '[=11=]';
}
else
{
mxGetString(cellElement2, strIn, buflen);
memcpy(&connections[cellItem-2][0], strIn, buflen);
}
}
if (cellItem == 10)
{
posXIn = mxGetPr(cellElement2);
memcpy(&posX,posXIn,sizeof(double));
}
if (cellItem == 11)
{
posYIn = mxGetPr(cellElement2);
memcpy(&posY,posYIn,sizeof(double));
}
if (cellItem == 12)
{
posXIn = mxGetPr(cellElement2);
memcpy(&wpX,posXIn,sizeof(double));
}
if (cellItem == 13)
{
posYIn = mxGetPr(cellElement2);
memcpy(&wpY,posYIn,sizeof(double));
}
if (cellItem == 14)
{
weightIn = mxGetPr(cellElement2);
memcpy(&weight,weightIn,sizeof(double));
}
}
sprintf(xStr,"%i",gridX);
sprintf(yStr,"%i",gridY);
sprintf(key,"%ix%i",gridX,gridY);
}
这就是我在 AStar.cpp
中初始化节点列表的方式
// Create nodes in the nodes hash
mxArray *cellElement;
std::map<std::string, Node> nodesHash;
for (int nodeID=0; nodeID < numberOfNodes; nodeID++)
{
cellElement = mxGetCell(prhs[0], nodeID);
Node n(cellElement);
nodesHash[n.key] = n;
}
Form now on nothing uses prhs[0] anything because nothing has altered the content prhs[0] (variable containing pointer to the Matlab variable cellNodes), 这个变量在离开后应该是完全一样的墨西哥
从这里我有两个问题:
- 如果没有任何内容改变第一个参数的内容,为什么当从 getWP returning 时它会崩溃?
- 是否有更优雅的方法强制 Matlab 创建变量的真实副本?
谢谢!
*Edit1:在 Windows10 64 位中使用 Matlab 2015b。
受到@CrisLuengo 和@JamesTursa 的喜爱。
1) 如果没有改变第一个参数的内容,为什么从 getWP 返回时会崩溃?
[Node.cpp] 'double* tempVal' 未分配,尽管代码有效,但这可能会破坏 prhs[0] 的完整性,从而导致 Matlab 在从调用的函数返回时崩溃墨西哥。
解决方案是将 tempVal 声明为 'double tempVal[1]'。
之后,可以删除 testAStarC.m 行 'cellNodes{keyID}.x = cellNodes{keyID}.x;' 而不会导致错误。
虽然与崩溃无关,但使用 memcpy 获取标量双精度已替换为 mxGetScalar()。
节点构造函数:
Node::Node(mxArray *cellElement)
{
char strIn[15];
double tempVal[1];
size_t numCellElms = mxGetNumberOfFields(cellElement);
mwSize buflen;
for (int cellItem = 0; cellItem < numCellElms; cellItem++)
{
mxArray *cellElement2 = mxGetCell(cellElement,cellItem);
switch (cellItem)
{
case 0:
gridX = (int)mxGetScalar(cellElement2);
break;
case 1:
gridY = (int)mxGetScalar(cellElement2);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
if (buflen <= 1)
connections[cellItem-2][0] = '[=10=]';
else
{
mxGetString(cellElement2, strIn, buflen);
memcpy(&connections[cellItem-2][0], strIn, buflen);
}
break;
case 10:
posX = mxGetScalar(cellElement2);
break;
case 11:
posY = mxGetScalar(cellElement2);
break;
case 12:
wpX = mxGetScalar(cellElement2);
break;
case 13:
wpY = mxGetScalar(cellElement2);
break;
case 14:
weight = mxGetScalar(cellElement2);
break;
}
}
sprintf(xStr,"%i",gridX);
sprintf(yStr,"%i",gridY);
sprintf(key,"%ix%i",gridX,gridY);
}
testAStarC.m
function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
% HashMap containing the nodes (this is a Java hashmap)
nodesHash = map.navMap.nodes.nodes;
keys = nodesHash.keys();
numNodes = length(keys);
cellNodes = cell(1,numNodes);
% Parse the nodes from the HashMap to Cells as the MEX seems to be
% unable to read directly from the Java HashMap
for keyID=1:numNodes
cellNodes{keyID} = nodesHash(keys{keyID});
end
waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);
2) 是否有更优雅的方法强制 Matlab 创建变量的真实副本?
不,你能做的最好的就是尝试分配技巧。
我正在创建一个 MEX,以使用 A* 算法找到两个节点之间的路径。代码按预期工作,检索到正确的结果,一切似乎都很好,但是当我从调用 MEX 的方法中 return 时,Matlab 只是自行关闭。
据我所知,有时当用户试图创建一个变量的副本时,Matlab 会创建一个指向相同内存地址的指针(即 A = 3;B = A,然后 A 和 B 指向相同的内存地址,即使 Matlab 将它们显示为 2 个自变量)我使用了一个老技巧,即直接对变量的副本执行操作,即使它很愚蠢,Matlab 也会认为这两个变量不再相同并且将创建它的副本(即 A = 3;B = A;B = B+0,现在 A 和 B 存储为不同的独立变量)。
因此,我发现解决此问题的唯一方法是在函数 getWP 中执行如下所示的操作:
function testAStarC()
% load the map of the area
load('epsp0_2_nav.mat');
% Set the initial node
initNode = '16x21';
% Set the target node
finalNode = '-15x54';
% Select Heuristic
heuristic = 'Manhattan';
% Create a target location (targetX, targetY, targetAngle)
targetCoords = [-15*110 54*110 0.15];
% Function that hosts the call to the MEX
wp = getWP(map, initNode, finalNode, targetCoords, heuristic);
disp('If you remove the line cellNodes{keyID}.x = cellNodes{keyID}.x; from getWP ...
I wont reach this line');
disp(['Route with ',num2str(length(wp)),' wp found']);
disp('done');
function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
% HashMap containing the nodes (this is a Java hashmap)
nodesHash = map.navMap.nodes.nodes;
keys = nodesHash.keys();
numNodes = length(keys);
cellNodes = cell(1,numNodes);
% Parse the nodes from the HashMap to Cells as the MEX seems to be
% unable to read directly from the Java HashMap
for keyID=1:numNodes
cellNodes{keyID} = nodesHash(keys{keyID});
%---------------------------------------------------------
% WITHOUTH THIS MATLAB CRASHES WHEN RETURNING FROM GETWP
%---------------------------------------------------------
% We need this to force Matlab to create a new copy of the content,
% otherwise will send a pointer aiming to the HashMap and crash when
% returning from getWP.
cellNodes{keyID}.x = cellNodes{keyID}.x;
end
waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);
disp('I am not crashing here if you remove cellNodes{keyID}.x = cellNodes{keyID}.x');
我的第一个想法是我在 MEX 中对“cellNodes”做错了什么,这导致 Matlab 崩溃,但我没有直接使用输入参数执行任何操作。这是节点 class:
的构造函数Node.cpp
Node::Node(mxArray *cellElement)
{
double *xIn;
double *yIn;
char strIn[15];
double *posXIn;
double *posYIn;
double *weightIn;
double *tempVal;
size_t numCellElms;
mxArray *cellElement2;
numCellElms = mxGetNumberOfFields(cellElement);
size_t size;
for (int cellItem = 0; cellItem < numCellElms; cellItem++)
{
cellElement2 = mxGetCell(cellElement,cellItem);
if (cellItem == 0)
{
xIn = mxGetPr(cellElement2);
memcpy(tempVal,xIn,sizeof(double));
gridX = int(*tempVal);
}
if (cellItem == 1)
{
yIn = mxGetPr(cellElement2);
memcpy(tempVal,yIn,sizeof(double));
gridY = int(*tempVal);
}
if (cellItem >= 2 && cellItem < 10)
{
mwSize buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
if (buflen <= 1)
{
connections[cellItem-2][0] = '[=11=]';
}
else
{
mxGetString(cellElement2, strIn, buflen);
memcpy(&connections[cellItem-2][0], strIn, buflen);
}
}
if (cellItem == 10)
{
posXIn = mxGetPr(cellElement2);
memcpy(&posX,posXIn,sizeof(double));
}
if (cellItem == 11)
{
posYIn = mxGetPr(cellElement2);
memcpy(&posY,posYIn,sizeof(double));
}
if (cellItem == 12)
{
posXIn = mxGetPr(cellElement2);
memcpy(&wpX,posXIn,sizeof(double));
}
if (cellItem == 13)
{
posYIn = mxGetPr(cellElement2);
memcpy(&wpY,posYIn,sizeof(double));
}
if (cellItem == 14)
{
weightIn = mxGetPr(cellElement2);
memcpy(&weight,weightIn,sizeof(double));
}
}
sprintf(xStr,"%i",gridX);
sprintf(yStr,"%i",gridY);
sprintf(key,"%ix%i",gridX,gridY);
}
这就是我在 AStar.cpp
中初始化节点列表的方式// Create nodes in the nodes hash
mxArray *cellElement;
std::map<std::string, Node> nodesHash;
for (int nodeID=0; nodeID < numberOfNodes; nodeID++)
{
cellElement = mxGetCell(prhs[0], nodeID);
Node n(cellElement);
nodesHash[n.key] = n;
}
Form now on nothing uses prhs[0] anything because nothing has altered the content prhs[0] (variable containing pointer to the Matlab variable cellNodes), 这个变量在离开后应该是完全一样的墨西哥
从这里我有两个问题:
- 如果没有任何内容改变第一个参数的内容,为什么当从 getWP returning 时它会崩溃?
- 是否有更优雅的方法强制 Matlab 创建变量的真实副本?
谢谢!
*Edit1:在 Windows10 64 位中使用 Matlab 2015b。
受到@CrisLuengo 和@JamesTursa 的喜爱。
1) 如果没有改变第一个参数的内容,为什么从 getWP 返回时会崩溃?
[Node.cpp] 'double* tempVal' 未分配,尽管代码有效,但这可能会破坏 prhs[0] 的完整性,从而导致 Matlab 在从调用的函数返回时崩溃墨西哥。
解决方案是将 tempVal 声明为 'double tempVal[1]'。 之后,可以删除 testAStarC.m 行 'cellNodes{keyID}.x = cellNodes{keyID}.x;' 而不会导致错误。
虽然与崩溃无关,但使用 memcpy 获取标量双精度已替换为 mxGetScalar()。
节点构造函数:
Node::Node(mxArray *cellElement)
{
char strIn[15];
double tempVal[1];
size_t numCellElms = mxGetNumberOfFields(cellElement);
mwSize buflen;
for (int cellItem = 0; cellItem < numCellElms; cellItem++)
{
mxArray *cellElement2 = mxGetCell(cellElement,cellItem);
switch (cellItem)
{
case 0:
gridX = (int)mxGetScalar(cellElement2);
break;
case 1:
gridY = (int)mxGetScalar(cellElement2);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
if (buflen <= 1)
connections[cellItem-2][0] = '[=10=]';
else
{
mxGetString(cellElement2, strIn, buflen);
memcpy(&connections[cellItem-2][0], strIn, buflen);
}
break;
case 10:
posX = mxGetScalar(cellElement2);
break;
case 11:
posY = mxGetScalar(cellElement2);
break;
case 12:
wpX = mxGetScalar(cellElement2);
break;
case 13:
wpY = mxGetScalar(cellElement2);
break;
case 14:
weight = mxGetScalar(cellElement2);
break;
}
}
sprintf(xStr,"%i",gridX);
sprintf(yStr,"%i",gridY);
sprintf(key,"%ix%i",gridX,gridY);
}
testAStarC.m
function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
% HashMap containing the nodes (this is a Java hashmap)
nodesHash = map.navMap.nodes.nodes;
keys = nodesHash.keys();
numNodes = length(keys);
cellNodes = cell(1,numNodes);
% Parse the nodes from the HashMap to Cells as the MEX seems to be
% unable to read directly from the Java HashMap
for keyID=1:numNodes
cellNodes{keyID} = nodesHash(keys{keyID});
end
waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);
2) 是否有更优雅的方法强制 Matlab 创建变量的真实副本? 不,你能做的最好的就是尝试分配技巧。