关于对话框的多线程问题!! 问题很简单,一个对话框中进行很大量的计算,现在要停止不算了(如点‘关闭’或‘取消’),然后弹出对话框提示“真的要退出嘛,还没完成计算?”,点击‘确定’来退出,‘取消’不退出!很多程序都有这个功能,怎么用多线程实现呢?请说的具体点谢 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 启动一个worker线程,用事件对象在UI线程与worker线程之间同步,如果需要退出时可以触发事件来结束wordker线程。 哪位有类似的程序可以借小弟一看?信箱:[email protected] unit threadproc(lpvoid lpvoid){......}main(){......struct {int test;......} param;AfxBeginThread(threadproc, ¶m}......} DWORD CALLBACK CalculateProc(LPVOID p){ THREAD_PARAM *param = (THREAD_PARAM *)p; UINT n,result,i; HWND hProgressBar; n = param->n; result = 1; hProgressBar = ::GetDlgItem(param->hDlg,IDC_PROGRESS1); DWORD dwError = GetLastError(); for(i = 1; i <= n; i++) { result *= i; //显示进度 ::SendMessage(hProgressBar,PBM_SETPOS,100 * i / n,0); //看有没有取消的请求 if (WaitForSingleObject(param->hCancel,0) == WAIT_OBJECT_0) return 0; } param->result = result; return 0;}void CTempttDlg::OnCal() { UINT nID; DWORD dwID; nID = GetWindowLong(m_wndcal.m_hWnd,GWL_ID); if (nID == IDC_CAL) { if (m_param == NULL) m_param = new THREAD_PARAM; m_param->hDlg = this->m_hWnd; m_param->n = 2000000; m_param->hCancel = CreateEvent(NULL,FALSE,FALSE,NULL); ::SetWindowText(m_wndcal.m_hWnd,TEXT("取消计算")); ::SetWindowLong(m_wndcal.m_hWnd,GWL_ID,IDC_CANCLE); //启动计算线程 CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID); } else if (nID == IDC_CANCLE) { if (MessageBox(TEXT("真的要取消计算吗?"),TEXT("取消计算"),MB_YESNO) == IDYES) { SetEvent(m_param->hCancel); ::SetWindowText(m_wndcal.m_hWnd,TEXT("计算")); ::SetWindowLong(m_wndcal.m_hWnd,GWL_ID,IDC_CAL); m_progress.SetPos(0); } }}BOOL CTempttDlg::DestroyWindow() { if (m_param != NULL) delete m_param; return CDialog::DestroyWindow();}THREAD_PARAM 的定义:typedef struct{ HWND hDlg; UINT n; UINT result; HANDLE hCancel;}THREAD_PARAM;我把程序发到你的邮箱里去了。 当把线程函数的参数设置成结构体,编译也出错,提示为:cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗? 我是直接在对话框的OnOK()函数中创建进程:CreateThread(),但第三和第四个参数不知如何来处理? 当把线程函数的参数设置成结构体,编译也出错,提示为:cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗?_________________________________________________________这种错误估计是你的线程函数定义中掉了CALLBACK线程函数的定义应该是:DWORD CALLBACK ThreadProc(LPVOID param);其中CALLBACK就等于_stdcall 我是直接在对话框的OnOK()函数中创建进程:CreateThread(),但第三和第四个参数不知如何来处理?-------------------------------------------------------------------------------第三个参数是线程函数的地址,线程函数必须是全局函数或者类的静态函数。如果是类的静态函数的话,在创建线程的时候必须有相应的访问权限。线程函数返回值类型必须为DWORD,调用方式必须是_stdcall(用WINAPI或者CALLBACK修饰线程函数就可以使它的调用方式成为_stdcall)第四个参数是传给线程的参数。它的类型是LPVOID。但是用强制类型转换可以把任何类型的数据传送给线程作为参数的。例如,我上面给出的例子就把下面的结构体传给线程了:typedef struct{ HWND hDlg; UINT n; UINT result; HANDLE hCancel;}THREAD_PARAM;注意启动线程的函数调用:CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID);第四个参数是m_param,它是一个THREAD_PARAM类型的指针。线程里面使用它的方式是:DWORD CALLBACK CalculateProc(LPVOID p){ THREAD_PARAM *param = (THREAD_PARAM *)p; 为什么你的参数能传进来,而我的参数怎么也传不进来呢??帮忙看一下:主语句是:if(MDS1->GetCheck()) { m_param=new struct THREAD_PARA; m_param->APS_id=APS_file_id; m_param->OutputPath=m_strOutputFilePath; m_param->CHANNEL="MDS1";// CalibrationForOneDataset(APS_file_id,m_strOutputFilePath,"MDS1"); CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID); delete m_param; }进程函数是:DWORD CALLBACK CalculateProc(LPVOID p){ //为什么参数传不进来? THREAD_PARA *param = (THREAD_PARA *)p; CCalibrationDlg MyDlg;MyDlg.CalibrationForOneDataset(param->APS_id,param->OutputPath,param->CHANNEL); return 0;}编译的时候没有错误,但运行的时候param->OutputPath根本就是空的,甚至p->OutputPath就是空的,不知道为什么?! 不应该有这一句的:delete m_param;因为线程是并行执行的,你无法确定多个线程的执行次序(由操作系统决定)。那么可能的情况是:还没有执行到DWORD CALLBACK CalculateProc(LPVOID p){ //为什么参数传不进来? THREAD_PARA *param = (THREAD_PARA *)p;这儿来的时候,delete m_param;就被执行了,所以参数就传不进去了。 如果你想清除参数所占的内存,给两种方法你参考:1 在对话框的析构函数里面进行: if (m_param != NULL) delete m_param;2 在线程函数里面进行:DWORD CALLBACK CalculateProc(LPVOID p){ THREAD_PARA param = *((THREAD_PARA *)p);//复制参数 delete ((THREAD_PARA *)p); 难道两个语句不是按顺序执行的吗?把delete m_param删掉是可以把参数传进去,也能进入到线程中调用的函数CalibrationForOneDataset()中,但一进去就内存泄漏了! if(MDS1->GetCheck()) { m_param=new struct THREAD_PARA; // 1.声明时放到类里边,成为这个类的全局变量。之前要检查m_param是否为空,如果不为空,则释放内存后,再用 new m_param->APS_id=APS_file_id; m_param->OutputPath=m_strOutputFilePath; m_param->CHANNEL="MDS1";// CalibrationForOneDataset(APS_file_id,m_strOutputFilePath,"MDS1"); CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID); delete m_param; // 2. 这里不要这样子,把这一句删除掉。因为这一句执行以后,在线程内部都变成空的了 } m_param的声明放到类里边,在析构函数里,释放内存 在函数CalibrationForOneDataset()中有一条分配内存的语句,执行到这句就泄漏了,但如果不把该函数放到线程中处理,就不泄漏,这是为什么呀? 也就是说,在线程函数中调用了CalibrationForOneDataset(),而在该函数中有这样一句:gain= (float*)calloc(m_ulSceneWith,sizeof(float));其中m_ulSceneWith是一个几千的整数,每执行到这一句就出错,内存就满了,怎么解决? 用GlobalAlloc()试试如果还不行,就用VirtualAlloc()试试,详细资料见MSDN。 问题还没搞定呀,先散点儿分吧,等一下再来讨论,谢谢 yaozijian110先! 关于scrollwindow函数的问题 为什么函数声明时候,不需要实参,但定义时一定要实参 找工作 怎样把BYTE数组,转换为UNICODE的CString? 现金求电路图:无线短信终端的电路图 vc写的ocx控件使程序越来越慢 ----------- 解决者 ------- 100分 我很困惑... 菜鸟问题:OnKillActive和UpdateData两者对数据处理的区别在哪里? Receive(buf,sizeof(buf)),其中BUF的大小是不是不能超过24K 这样初始化没见过,麻烦各位大神指点下迷津! 各位大侠,关于DLL的问题给指条明路 100分,请大家帮帮我!!!
{
......
}main()
{
......
struct {
int test;
......
} param;AfxBeginThread(threadproc, ¶m}
......
}
DWORD CALLBACK CalculateProc(LPVOID p)
{
THREAD_PARAM *param = (THREAD_PARAM *)p;
UINT n,result,i;
HWND hProgressBar; n = param->n;
result = 1;
hProgressBar = ::GetDlgItem(param->hDlg,IDC_PROGRESS1);
DWORD dwError = GetLastError();
for(i = 1; i <= n; i++)
{
result *= i;
//显示进度
::SendMessage(hProgressBar,PBM_SETPOS,100 * i / n,0);
//看有没有取消的请求
if (WaitForSingleObject(param->hCancel,0) == WAIT_OBJECT_0)
return 0;
}
param->result = result;
return 0;
}void CTempttDlg::OnCal()
{
UINT nID;
DWORD dwID; nID = GetWindowLong(m_wndcal.m_hWnd,GWL_ID);
if (nID == IDC_CAL)
{
if (m_param == NULL) m_param = new THREAD_PARAM; m_param->hDlg = this->m_hWnd;
m_param->n = 2000000;
m_param->hCancel = CreateEvent(NULL,FALSE,FALSE,NULL);
::SetWindowText(m_wndcal.m_hWnd,TEXT("取消计算"));
::SetWindowLong(m_wndcal.m_hWnd,GWL_ID,IDC_CANCLE);
//启动计算线程
CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID);
}
else if (nID == IDC_CANCLE)
{
if (MessageBox(TEXT("真的要取消计算吗?"),TEXT("取消计算"),MB_YESNO) == IDYES)
{
SetEvent(m_param->hCancel);
::SetWindowText(m_wndcal.m_hWnd,TEXT("计算"));
::SetWindowLong(m_wndcal.m_hWnd,GWL_ID,IDC_CAL);
m_progress.SetPos(0);
}
}
}BOOL CTempttDlg::DestroyWindow()
{
if (m_param != NULL) delete m_param;
return CDialog::DestroyWindow();
}
THREAD_PARAM 的定义:
typedef struct
{
HWND hDlg;
UINT n;
UINT result;
HANDLE hCancel;
}THREAD_PARAM;我把程序发到你的邮箱里去了。
cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗?
cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗?
_________________________________________________________
这种错误估计是你的线程函数定义中掉了CALLBACK
线程函数的定义应该是:
DWORD CALLBACK ThreadProc(LPVOID param);
其中CALLBACK就等于_stdcall
-------------------------------------------------------------------------------
第三个参数是线程函数的地址,线程函数必须是全局函数或者类的静态函数。如果是类的静态函数的话,在创建线程的时候必须有相应的访问权限。
线程函数返回值类型必须为DWORD,调用方式必须是_stdcall(用WINAPI或者CALLBACK修饰线程函数就可以使它的调用方式成为_stdcall)第四个参数是传给线程的参数。它的类型是LPVOID。但是用强制类型转换可以把任何类型的数据传送给线程作为参数的。例如,我上面给出的例子就把下面的结构体传给线程了:
typedef struct
{
HWND hDlg;
UINT n;
UINT result;
HANDLE hCancel;
}THREAD_PARAM;
注意启动线程的函数调用:
CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID);
第四个参数是m_param,它是一个THREAD_PARAM类型的指针。
线程里面使用它的方式是:
DWORD CALLBACK CalculateProc(LPVOID p)
{
THREAD_PARAM *param = (THREAD_PARAM *)p;
if(MDS1->GetCheck())
{
m_param=new struct THREAD_PARA;
m_param->APS_id=APS_file_id;
m_param->OutputPath=m_strOutputFilePath;
m_param->CHANNEL="MDS1";
// CalibrationForOneDataset(APS_file_id,m_strOutputFilePath,"MDS1");
CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID);
delete m_param;
}进程函数是:
DWORD CALLBACK CalculateProc(LPVOID p)
{ //为什么参数传不进来?
THREAD_PARA *param = (THREAD_PARA *)p;
CCalibrationDlg MyDlg;
MyDlg.CalibrationForOneDataset(param->APS_id,param->OutputPath,param->CHANNEL);
return 0;
}
编译的时候没有错误,但运行的时候param->OutputPath根本就是空的,甚至p->OutputPath就是空的,不知道为什么?!
因为线程是并行执行的,你无法确定多个线程的执行次序(由操作系统决定)。
那么可能的情况是:
还没有执行到
DWORD CALLBACK CalculateProc(LPVOID p)
{ //为什么参数传不进来?
THREAD_PARA *param = (THREAD_PARA *)p;
这儿来的时候,delete m_param;就被执行了,所以参数就传不进去了。
if (m_param != NULL) delete m_param;2 在线程函数里面进行:
DWORD CALLBACK CalculateProc(LPVOID p)
{
THREAD_PARA param = *((THREAD_PARA *)p);//复制参数
delete ((THREAD_PARA *)p);
{
m_param=new struct THREAD_PARA; // 1.声明时放到类里边,成为这个类的全局变量。之前要检查m_param是否为空,如果不为空,则释放内存后,再用 new
m_param->APS_id=APS_file_id;
m_param->OutputPath=m_strOutputFilePath;
m_param->CHANNEL="MDS1";
// CalibrationForOneDataset(APS_file_id,m_strOutputFilePath,"MDS1");
CreateThread(NULL,0,CalculateProc,(LPVOID)m_param,0,&dwID);
delete m_param; // 2. 这里不要这样子,把这一句删除掉。因为这一句执行以后,在线程内部都变成空的了
}
如果还不行,就用VirtualAlloc()试试,详细资料见MSDN。