I had an earlier question about integrating Mathematica with functions written in C++.
这是一个后续问题:
如果计算时间太长,我希望能够使用 Evaluation>中止它。中止评估。答案中建议的哪些技术可以实现可中断的基于C的扩展功能?如何在C方面实施“可中断性”?
我需要以一种既不会破坏它,也不会破坏Mathematica内核的方式使我的函数可中断(即应该可以在Mathematica被中断后再次调用该函数)
答案 0 :(得分:5)
对于基于MathLink的函数,您必须做两件事(在Windows上):使用MLAbort
检查中止,并调用MLCallYieldFunction
,暂时生成处理器。两者都在Todd Gayley的MathLink教程中描述,可以追溯到here。
使用我之前答案中的位,这里是一个计算素数的示例代码(以低效的方式,但这是我们在这里需要的例子):
code =
"
#include <stdlib.h>
extern void primes(int n);
static void yield(){
MLCallYieldFunction(
MLYieldFunction(stdlink),
stdlink,
(MLYieldParameters)0 );
}
static void abort(){
MLPutFunction(stdlink,\" Abort \",0);
}
void primes(int n){
int i = 0, j=0,prime = 1, *d = (int *)malloc(n*sizeof(int)),ctr = 0;
if(!d) {
abort();
return;
}
for(i=2;!MLAbort && i<=n;i++){
j=2;
prime = 1;
while (!MLAbort && j*j <=i){
if(i % j == 0){
prime = 0;
break;
}
j++;
}
if(prime) d[ctr++] = i;
yield();
}
if(MLAbort){
abort();
goto R1;
}
MLPutFunction(stdlink,\"List\",ctr);
for(i=0; !MLAbort && i < ctr; i++ ){
MLPutInteger(stdlink,d[i]);
yield();
}
if(MLAbort) abort();
R1: free(d);
}
";
和模板:
template =
"
void primes P((int ));
:Begin:
:Function: primes
:Pattern: primes[n_Integer]
:Arguments: { n }
:ArgumentTypes: { Integer }
:ReturnType: Manual
:End:
";
以下是创建程序的代码(取自上一个答案,略有修改):
Needs["CCompilerDriver`"];
fullCCode = makeMLinkCodeF[code];
projectDir = "C:\\Temp\\MLProject1";
If[! FileExistsQ[projectDir], CreateDirectory[projectDir]]
pname = "primes";
files = MapThread[
Export[FileNameJoin[{projectDir, pname <> #2}], #1,
"String"] &, {{fullCCode, template}, {".c", ".tm"}}];
现在,我们在这里创建它:
In[461]:= exe=CreateExecutable[files,pname];
Install[exe]
Out[462]= LinkObject["C:\Users\Archie\AppData\Roaming\Mathematica\SystemFiles\LibraryResources\
Windows-x86-64\primes.exe",161,10]
并使用它:
In[464]:= primes[20]
Out[464]= {2,3,5,7,11,13,17,19}
In[465]:= primes[10000000]
Out[465]= $Aborted
在后一种情况下,我使用了Alt +“。”中止计算请注意,如果您不包含对yield
的调用,则无法正常工作。
一般的意识形态是你必须检查MLAbort
并为每个昂贵的计算调用MLCallYieldFunction
,例如大循环等。也许,就像我上面那样对内循环这样做是一种矫枉过正虽然。您可以尝试做的一件事是使用C预处理器(宏)将样板代码分解。
答案 1 :(得分:3)
如果没有尝试过,看起来Expression Packet功能可能会以这种方式运行 - 如果您的C代码返回并要求mathematica定期执行更多工作,那么希望在mathematica端中止执行将告诉C代码,没有更多的工作要做。
答案 2 :(得分:3)
如果您使用LibraryLink将外部C代码链接到Mathematica内核,则可以使用库回调函数AbortQ来检查是否正在进行中止。