您的位置:首页 > 其它

AfxBeginThread函数参数传递的问题

2014-05-06 22:45 477 查看
转载自:http://blog.csdn.net/oceanlucy/article/details/7345057

AfxBeginThread函数参数传递的问题

一、背景

最近接手一个软件开发项目,该软件需要同时启动多个线程进行订单作业,而且每个订单可能会处理大批量数据,运行起来时内存占用率有可能会比较大,所以采用多线程作业。同时由于每个线程都会调用某些公用的动态库或全局变量,如果某个动态库不支持多线程调用,如动态库中定义了多个全局变量,则多个线程同时作业时会出现数值错误,所以应该通过函数AfxBeginThread()来进行参数传递,每个线程独自分开处理。

二、AfxBeginThread函数知识

1、AfxBeginThread的原型有两个,一个是用户界面(user-interface)线程,一个是工作者(worker)线程。以下重点介绍工作者线程,其原型如下所示。

CWinThread* AFXAPI AfxBeginThread(

AFX_THREADPROC pfnThreadProc,

LPVOID pParam,

int nPriority,

UINT nStackSize,

DWORD dwCreateFlags,

LPSECURITY_ATTRIBUTES lpSecurityAttrs)

其中:

参数1 :指向工作者线程的控制函数,其值不能为空,声明方式为UINT MyControllingFunc( LPVOID pParam )。

参数2 :传入到控制函数的参数(即pfnThreadProc对应的函数),它的类型为LPVOID。

参数3:指定线程的优先级。

参数4:指定新创建线程的堆栈大小(bytes),如果为0,则默认与创建该线程的线程相同。

参数5:是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则如果该值为0,则线程在创建后立即开始线程的执行。

参数6:指定线程的安全属性,如果该值为NULL,则与创建该线程的线程相同。NT下有用。

返回值:返回新创建的线程指针。

注意:

UINT MyControllingFunction( LPVOID pParam )函数必须声明为全局函数或者静态成员函数。
在进行多线程编程时,传入到控制函数里的变量尽可能不要使用全局变量,考虑用参数传入到控制函数中。

三、具体实现

对于线程函数中参数的传递,我们这里定义一个结构体类型,用new运算符申请内存并用该指针来传递。

1、函数和结构体全局声明

UINT MyControllingFunction(LPVOID lpParam);

//transfer parameter to thread

typedef struct SthData

{

ungsigned char ucOrderNumber[255];

ungsigned char ucOrderID[255];

}*pSthData;

2、结构体赋值

//pass parameters to thread

pSthData pDataValue = new SthData;

memset(pDataValue, 0x00, sizeof(SthData));

memcpy(pDataValue->ucOrderID, strOrderID.GetBuffer(strOrderID.GetLength()), strOrderID.GetLength());

memcpy(pDataValue->ucOrderNumber,strTask_No.GetBuffer(strTask_No.GetLength()),strTask_No.GetLength());

strOrderID.ReleaseBuffer(-1);

strTask_No.ReleaseBuffer(-1);

//create thread

CWinThread* pThread;

pThread = AfxBeginThread(MyControllingFunction, pDataValue);

delete stcSthData;

stcSthData = NULL;

3、线程内调用

UINT MyControllingFunction(LPVOID lpParam)

{

SthData* stcSthDataData = (SthData *)lpParam;

strOrderID = stcSthDataData->ucOrderID;

strOrderNum = stcSthDataData->ucOrderNumber;

......

......

}

4、结果

点击“运行”按钮后,调试时发现传递进来的参数ucOrderID和ucOrderNumber为乱码,以致于strOrderID和strOrderNum 的值为空。

怎么回事呢?

原来问题就出现在AfxBeginThread(MyControllingFunction, pDataValue)函数后的语句:delete stcSthData。当程序执行到AfxBeginThread(MyControllingFunction, pDataValue)函数这一步时,程序会创建一个进程,并调用MyControllingFunction线程函数,但是同时也会往下执行代码语句,即delete stcSthData。我们知道,用new 运算符可以动态分配内存,而且必须与delete 配对使用。当使用delete运算符时,它会释放撤销刚刚申请的内存地址空间,即会把指向结构体地址所对应的内存释放,导致我们看到的乱码。

5、解决办法

delete stcSthData;

stcSthData = NULL;

应该把以上语句放入到线程函数体内。

UINT MyControllingFunction(LPVOID lpParam)

{

SthData* stcSthDataData = (SthData *)lpParam;

strOrderID = stcSthDataData->ucOrderID;

strOrderNum = stcSthDataData->ucOrderNumber;

delete stcSthData;

stcSthData = NULL; //防止野指针

......

......

}

四、其它

1、线程函数中使用类成员或函数

我们可以把this指针作为参数传递给线程函数,如AfxBeginThread(MyControllingFunction, this)。
如果我们不想传递参数,则可以定义一个全局变量CWnd * cwind;然后在初始化函数中把this指针赋给它,如cwind = this;最后在线程函数UINT MyControllingFunction(LPVOID lpParam)中强制进行类型转换,如下所示:

cwind = this;

UINT MyControllingFunction(LPVOID lpParam)

{

CString strOrderID;

CSthDataDlg *cDlg = (CSthDataDlg *)cwind;

strOrderID = cDlg->m_strOrderID;

.......

.......

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: