【问题标题】:Access to main dialog variables within thread (MFC)访问线程内的主对话框变量 (MFC)
【发布时间】:2015-06-25 08:05:53
【问题描述】:

我有一个带有 MFC 的 GUI 应用程序。我正在使用 AfxBeginThread() 启动线程来处理一些数据。而且我在访问线程中的主对话框时遇到问题:

通过这个结构,我将主对话框处理程序和指向主 dlg 对象的指针传递给线程。但在 strcpy() 行调试器停止并显示 pDlg->0x430f0020 {CTabDlg hWnd=???}

typedef struct {
    LPVOID myHandle;
    LPVOID myPointer;
} sParamData;


UINT WorkerThreadProc_type2( LPVOID Param )
{


    UpdInfo info;   
    sParamData *s;

    s = (sParamData*)Param;
    HWND hMainHandle = (HWND) (*s).myHandle;
    CtabDlg* pDlg = (CtabDlg*)(*s).myPointer;

    strcpy(apikey, pDlg->m_sVar);
...
}

我尝试了 XP 和 Windows 7 操作系统。在 XP 中它总是崩溃,但在七中它可以工作。这就是我将结构传递给线程的方式:

sParamData s;
    s.myHandle = (HWND)GetSafeHwnd();
    s.myPointer = (CtabDlg*) this;

    if(CurrTab == 1)
    {
        AfxBeginThread(WorkerThreadProc_type2, &s, THREAD_PRIORITY_NORMAL,0,0,NULL);
        pPage2->GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);

感谢您的宝贵时间!

【问题讨论】:

  • 一些与程序崩溃无关的备注:sParamData不应包含LPVOID类型,而是实际类型,即HWNDCtabDlg。这将避免对这些类型的所有强制转换。此外写s->myHandle而不是(*s).myHandle,它是等价的,但没有C程序员写(*s).而不是s->
  • 它可能是race condition,即在某些时候CTabDlg 不再存在,但您的线程不知道这一点。
  • @Michael Walz,CTabDlg 是一个主对话框,一直存在,而且它总是以某种方式在 Windows 7 中工作。
  • 好的,但是在某些情况下,比赛条件很可能会在一个平台上导致问题,但在另一个平台上却没有,顺便说一句:你在哪里声明 sParamData *s
  • 在 W7 上,线程似乎开始得早一点,所以当你从线程中读取变量 s 时,它仍然存在,而在 XP 上,线程似乎开始得晚一点,s当线程尝试读取它时不再存在。竞争条件的典型案例。

标签: c++ multithreading visual-c++ mfc


【解决方案1】:

如果您的代码与您的实际情况完全相同,那么您在这里声明一个本地 sParamData 并将其地址传递给线程。这给出了一个竞争条件: s 可以在线程开始执行之前超出范围,(或到达其内容被复制的点)。

sParamData s;
s.myHandle = (HWND)GetSafeHwnd();
s.myPointer = (CtabDlg*) this;

if(CurrTab == 1)
{
    AfxBeginThread(WorkerThreadProc_type2, &s, THREAD_PRIORITY_NORMAL,0,0,NULL);
    pPage2->GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);

最简单的解决方法可能是在堆上分配 s 并在其内容被复制后在线程中删除它。

像这样:

sParamData *s = new sParamData ;
s->myHandle = (HWND)GetSafeHwnd();
s->myPointer = (CtabDlg*) this;

if(CurrTab == 1)
{
    AfxBeginThread(WorkerThreadProc_type2, s, THREAD_PRIORITY_NORMAL,0,0,NULL);
    pPage2->GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);

然后,在线程内部

UINT WorkerThreadProc_type2( LPVOID Param )
{
    UpdInfo info;   
    sParamData *s = (sParamData*)Param;
    HWND hMainHandle = (HWND) s->myHandle;
    CtabDlg* pDlg = (CtabDlg*)s->.myPointer;
    // assuming s will no longer be used you can delete it here
    delete s ;

【讨论】:

  • 我在主 dlg 类中声明了 sParamData 并在 OnInitDialog() 中对其进行了初始化,现在它可以正常工作了,但是您能否向我展示一个代码示例,该示例将以“应该以正确的方式完成,请。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多