问题很简单,一个对话框中进行很大量的计算,现在要停止不算了(如点‘关闭’或‘取消’),然后弹出对话框提示“真的要退出嘛,还没完成计算?”,点击‘确定’来退出,‘取消’不退出!很多程序都有这个功能,怎么用多线程实现呢?请说的具体点

解决方案 »

  1.   

    启动一个worker线程,用事件对象在UI线程与worker线程之间同步,如果需要退出时可以触发事件来结束wordker线程。
      

  2.   

    哪位有类似的程序可以借小弟一看?信箱:[email protected]
      

  3.   

    unit threadproc(lpvoid lpvoid)
    {
    ......
    }main()
    {
    ......
    struct {
    int test;
    ......
    } param;AfxBeginThread(threadproc, &param}
    ......
    }
      

  4.   


    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;我把程序发到你的邮箱里去了。
      

  5.   

    当把线程函数的参数设置成结构体,编译也出错,提示为:
    cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗?
      

  6.   

    我是直接在对话框的OnOK()函数中创建进程:CreateThread(),但第三和第四个参数不知如何来处理?
      

  7.   

    当把线程函数的参数设置成结构体,编译也出错,提示为:
    cannot convert parameter 3 from 'long (long)' to 'unsigned long (__stdcall *)(void *)难道第三个参数(线程所调用函数的参数)有什么特殊的类型要求吗?线程函数的返回值类型有什么特殊要求吗?
    _________________________________________________________
    这种错误估计是你的线程函数定义中掉了CALLBACK
    线程函数的定义应该是:
    DWORD CALLBACK ThreadProc(LPVOID param);
    其中CALLBACK就等于_stdcall
      

  8.   

    我是直接在对话框的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;
      

  9.   

    为什么你的参数能传进来,而我的参数怎么也传不进来呢??帮忙看一下:主语句是:
    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就是空的,不知道为什么?!
      

  10.   

    不应该有这一句的:delete m_param;
    因为线程是并行执行的,你无法确定多个线程的执行次序(由操作系统决定)。
    那么可能的情况是:
    还没有执行到
    DWORD CALLBACK CalculateProc(LPVOID p)
    {   //为什么参数传不进来?
    THREAD_PARA *param = (THREAD_PARA *)p;
    这儿来的时候,delete m_param;就被执行了,所以参数就传不进去了。
      

  11.   

    如果你想清除参数所占的内存,给两种方法你参考:1  在对话框的析构函数里面进行:
      if (m_param != NULL) delete m_param;2 在线程函数里面进行:
    DWORD CALLBACK CalculateProc(LPVOID p)
    {   
        THREAD_PARA param = *((THREAD_PARA *)p);//复制参数
        delete ((THREAD_PARA *)p);
      

  12.   

    难道两个语句不是按顺序执行的吗?把delete m_param删掉是可以把参数传进去,也能进入到线程中调用的函数CalibrationForOneDataset()中,但一进去就内存泄漏了!
      

  13.   

    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. 这里不要这样子,把这一句删除掉。因为这一句执行以后,在线程内部都变成空的了
    }
      

  14.   

    m_param的声明放到类里边,在析构函数里,释放内存
      

  15.   

    在函数CalibrationForOneDataset()中有一条分配内存的语句,执行到这句就泄漏了,但如果不把该函数放到线程中处理,就不泄漏,这是为什么呀?
      

  16.   

    也就是说,在线程函数中调用了CalibrationForOneDataset(),而在该函数中有这样一句:gain= (float*)calloc(m_ulSceneWith,sizeof(float));其中m_ulSceneWith是一个几千的整数,每执行到这一句就出错,内存就满了,怎么解决?
      

  17.   

    用GlobalAlloc()试试
    如果还不行,就用VirtualAlloc()试试,详细资料见MSDN。
      

  18.   

    问题还没搞定呀,先散点儿分吧,等一下再来讨论,谢谢 yaozijian110先!