I had an earlier question about integrating Mathematica with functions written in C++.
这是一个后续问题:
如果计算时间太长,我希望能够使用Evaluation>中止它.中止评估.答案中建议的哪些技术可以实现可中断的基于C的扩展功能?如何在C端实施“可中断性”?
我需要以一种既不会破坏它,也不会损坏Mathematica内核的方式使我的函数可中断(即应该可以在Mathematica被中断后再次调用该函数)
解决方法
对于基于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预处理器(宏)将样板代码分解.