C++ xll函数的线程安全性

C++ xll函数的线程安全性,c++,excel,multithreading,thread-safety,xll,C++,Excel,Multithreading,Thread Safety,Xll,我有一个愚蠢的xll函数: __declspec(dllexport) long F(long arg1, long arg2) { return arg1 + arg2; } __declspec(dllexport) LPXLOPER12 WINAPI G(LPXLOPER12 arrayin1, LPXLOPER12 arrayin2) { static XLOPER12 xlArray; // the reference to this one is going to

我有一个愚蠢的xll函数:

__declspec(dllexport) long F(long arg1, long arg2)
{
    return arg1 + arg2;
}
__declspec(dllexport) LPXLOPER12 WINAPI G(LPXLOPER12 arrayin1, LPXLOPER12 arrayin2)
{
    static XLOPER12 xlArray; // the reference to this one is going to be returned
    // treating arrayin1 and arrayin2 and outputting something in xlArray
    return static_cast<LPXLOPER12>(&xlArray);
}
我想它没有问题,生成的excel函数将是线程安全的

但是一个接受数组并返回数组的函数呢?例如考虑函数:

__declspec(dllexport) long F(long arg1, long arg2)
{
    return arg1 + arg2;
}
__declspec(dllexport) LPXLOPER12 WINAPI G(LPXLOPER12 arrayin1, LPXLOPER12 arrayin2)
{
    static XLOPER12 xlArray; // the reference to this one is going to be returned
    // treating arrayin1 and arrayin2 and outputting something in xlArray
    return static_cast<LPXLOPER12>(&xlArray);
}
Complex
是一个经典的复数类,“内存”函数如下(注意它是旧的C代码):

#包括“stdafx.h”
#包括
#包括“memory.h”
#包括
#包括“XLCALL.H”
#包括
void FromCharPtrToWChartPtr(char*from,XCHAR**to)
{
尺寸长度=标准长度(从);
*to=新的XCHAR[len+1];
*至[0]=静态_转换(len);
如果(len>0)
{
mbstowcs(*至+1,自,len+1);
}
}
void FromWChartPtrToWharPtr(XCHAR*from,char**to)
{
尺寸长度=从[0];
*to=新字符[len+1];
wcstombs(*至,自+1,len);
}
类型定义结构对象
{
字符*名称;
int version;/*对于每个新的存储操作,增量为1*/
作废*数据;
作废*下一步;
}托宾;
静态TObject*cache=NULL;
#定义分隔符“#”
ToObject*FindNode(字符*名称)
{
TObject*node=cache;
while(节点)
{
如果(_stricmp(节点->名称,名称)==0)
打破
节点=(TObject*)节点->下一步;
}
返回节点;
}
#定义故障-1
#定义成功0
char*StoreObject(char*name,void*data)
{
静态字符*routine=“StoreObject”;
int状态=故障;
char*handle=NULL;
TObject*节点;
静态字符缓冲区[255];
如果(数据==NULL)
{
//要稍后处理的错误
去做;
}
if(name==NULL)
{
//要稍后处理的错误
去做;
}
如果(strlen(名称)>200)
{
//要稍后处理的错误
去做;
}
node=FindNode(名称);
if(node==NULL)
{
node=newtobject();
if(node==NULL)
去做;
节点->名称=_strdup(名称);
节点->版本=1;
节点->数据=数据;
节点->下一步=缓存;
缓存=节点;
}
其他的
{
节点->版本+=1;
delete node->data;//是否应该对对象进行不同的销毁?
节点->数据=数据;
}
sprintf(缓冲区,“%s%c%d\0”,节点->名称,分隔符,节点->版本);
句柄=_strdup(缓冲区);
if(handle==NULL)
去做;
strcpy(手柄、缓冲器);
状态=成功;
完成:
如果(状态!=成功)
{
//要稍后处理的错误
删除句柄;
handle=NULL;
}
返回手柄;
}
void*RetrieveObject(char*handle)
{
静态字符*routine=“RetrieveObject”;
int状态=故障;
void*data=NULL;
char*name=NULL;
TObject*节点;
char*sep;
if(handle==NULL)
{
//要稍后处理的错误
去做;
}
名称=_strdup(句柄);
if(name==NULL)
去做;
/*从查找字符串中删除版本号*/
sep=strchr(名称、分隔符);
如果(sep!=NULL)
*sep='\0';
node=FindNode(名称);
if(node==NULL)
{
//要稍后处理的错误
去做;
}
数据=节点->数据;
状态=成功;
完成:
如果(状态!=成功)
{
//要稍后处理的错误
数据=空;
}
删除姓名;
返回数据;
}
void FreeObjects()
{
TObject*next=缓存;
TObject*节点;
while(下一个)
{
节点=下一个;
下一步=(TObject*)节点->下一步;
删除节点->名称;
删除节点->数据;
删除节点;
}
}

上有一个很好的演示,实际上static不是线程安全的,您需要将新变量分配给线程本地安全内存。您可以查看上述页面中的函数
get\u thread\u local\u xloper12

有一个很好的演示,实际上static不是线程安全的,您需要将新变量分配给线程本地安全内存。您可以查看上述页面中的函数
get\u thread\u local\u xloper12

将其设置为非静态并分配内存?将其设置为非静态并分配内存?Thx,之后我将查看并验证您的答案。奇怪的是,链接代码被称为C是但是香草C++。我用以实现返回“句柄”的函数,并把“句柄”作为参数,处理在内存中的对象标签。您认为该框架适合多线程吗?今晚晚些时候我将发布代码是的,如果相关的内存和代码本身是线程安全的(用关键部分锁定),但它可能很难实现,请小心死锁。在您的情况下,我更愿意将函数标记为非线程安全,以避免句柄的所有潜在问题…您的缓存不是线程安全的,您需要使用锁来保护每个操作(查找、检索、释放…),以防止多个线程同时修改缓存的状态。Ok thx,我从来没有真正学会编写线程安全代码,我想我不得不这么做,我会看一看,然后验证你的答案。奇怪的是,链接代码被称为C是但是香草C++。我用以实现返回“句柄”的函数,并把“句柄”作为参数,处理在内存中的对象标签。您认为该框架适合多线程吗?今晚晚些时候我将发布代码是的,如果相关的内存和代码本身是线程安全的(用关键部分锁定),但它可能很难实现,请小心死锁。在您的情况下,我更愿意将函数标记为非线程安全,以避免句柄的所有潜在问题…您的缓存不是线程安全的,您需要使用锁来保护每个操作(查找、检索、释放…),以防止多个线程同时修改缓存的状态。Ok thx,我从来没有真正学会编写线程安全代码,我想我是