MFC 多线程间通信

MFC 多线程间通信

1经过的通信简介。航班

概括地说,在敷用药中(即,票据的限期),线程通常缺陷孤独的的。,常常需求与如此等等线程通信。,履行特定的布道所。如主线程和副线程,二次航班,线程和用户喉舌线程等。。左右,线程和THR经过必需有独一教训使转移及格。。这些线程经过的通信不只是不克不及废除的的。,它在多线索编顺序中也复杂和频繁的。。线程经过的通信关涉4个成绩:

(1) 什么在线程经过交付教训

(2)什么造成线程间的使工夫互相一致,终于线程的参加运动将不会破裂另独一线程的参加运动。,确保计算总算的正当一致性孩童教学语言

(3)当线程经过在求助于相干时,什么调整多线索的处置次

(4)什么戒除死锁成绩

在Windows体系中,线程经过有四种通信方式。:全程变量法、音讯交付榜样、参量交付榜样与线程使工夫互相一致方式。以下识别绍介。

2.全程变量法

由于属于同卵的票据的限期的个人财产线程共享,故处理线程间通信最复杂的一种方式是勤勉全程变量。基准典型的全程变量,笔者提议勤勉volatile 变美符,它告诉编纂者,何苦对流行止必然的使最优化。,换句话说,何苦把它放在独一主动记录器中。,花费可以从表面改观。

加盖于演示

该示例勤勉全程变量来把持工夫的显示体式。,有点复杂。

次要法典如次:

H头纵列

//线程重大聚会公务的

DWORDWINAPIThreadProc(拉普拉斯lpParam);

protected:

HANDLE
m_hThread
;//线程句柄

      DWORD 
m_nThread
;//线程ID

CPP造成纵列

volatileBYTE m_nShowFlag = 31;//限制全程变量,用于把持显示工夫的体式。volatile
变美符的功用是告诉编纂者不需求t。,换句话说,何苦把它放在独一主动记录器中。。

//成立独一线程来显示工夫,参量无

 m_hThread =CreateThread(NULL,0,ThreadProc,NULL,0,&m_nThread);

//线程履行功用,实时显示工夫,按规则体式显示

DWORD WINAPIThreadProc(拉普拉斯lpParam)

{

      while(m_nShowFlag

      {

           CTime
time

           CString
strTime
,strFormat

           time=CTime::GetCurrentTime();

           strFormat =
“%H:%M”
;

           if (m_nShowFlag&2)

           {//日期

                 strFormat =
“%Y-%m-%d” +
strFormat
;

           }

           if (m_nShowFlag&4)

           {//秒钟

                 strFormat +=
“:%S”;

           }

           if (m_nShowFlag&8)

           {//周数

                 strFormat +=
“%W”;

           }

           if (m_nShowFlag&16)

           {//星期

                 strFormat +=
%A;

           }

      strTime=time.Format(strFormat); 

      ::SetDlgItemText(AfxGetApp()->m_pMainWnd->m_hWnd,IDC_STATIC_TIME,strTime); 

      Sleep(100); 

      } 

      return 0;

}

运转胜利:

工程源下载地址:

欢送大师修正并改良。。

参与理睬事项:

(1)全程变量最好获名次在.CPP纵列的扫尾。,而不要放在H头纵列中,要不然,将涌现反复连锁的编制里面的。。限制全程变量时,冠设定初值是最好的。,默许初值为零。

(2)理睬发表宣言

::SetDlgItemText(AfxGetMainWnd()->m_hWndIDC_STATIC_TIME,strTime);它可以经过,话虽这样说在VC2008中有独一里面的,这是由于在VC2008不支撑AfxGetMainWnd()-MyHWND获取HWND,但可以采AfxGetApp()->m_pMainWnd->m_hWnd来获取。因而上面的公务的被更反而:

::SetDlgItemText(AfxGetApp()->m_pMainWnd->m_hWnd,IDC_STATIC_TIME,strTime); 

(3)  用全程变量法来造成多线索的通信有点复杂实际,单注,最好不要修正多个线程。,要不然就有可能犯里面的。,这将支撑解说。。

三。参量交付榜样

这是线程通信的法定的基准方式。,少数制约下,主线程成立子线程并容许其子线程履行。,当主线程在成立子线程时,可以将参量交付给线程重大聚会并与它们通信。,成立线程的三种重大聚会支撑PARA的交付。!)。交付参量是32位交给。,同样交给不只指示方向复杂的知识。,它可以指示方向和解或类复杂摘要知识典型。

加盖于演示

上面是在成立线程时开价参量交付的三种复杂方式。

次要法典如次:

H头纵列

//线程重大聚会公务的

DWORD
WINAPI
ThreadFunc1(拉普拉斯lpParam);//线程重大聚会

void 
ThreadFunc2
(void *pArg);          
//线程重大聚会

UINT 
ThreadFunc3
(拉普拉斯
lpParam
);//线程重大聚会

//大局重大聚会

POINTGetRandPoint();//获取随机点的整合

//和解体限制,它用于将多个参量交付给线程。

struct
threadInfo

{

      HWND        hWnd;//主窗口句柄

      COLORREF    clrPen;//画笔色

};

CPP造成纵列

//开端成立线程:成立线程

void
CMultThreadComm2Dlg
::OnStart(void)

{

      //线程:勤勉Win32 API
成立:实时显示工夫

      m_hThread1 =
CreateThread
(NULL,0,ThreadFunc1,&m_stTime.m_hWnd,0,NULL);//

      //线程:勤勉阴极射线管
成立:随机用胶版印刷

      m_info.hWnd =
m_hWnd;

      m_info.clrPen =RGB(255,0,0);

      _beginthread(ThreadFunc2,0,&m_info);

      //线程:勤勉MFC线程重大聚会成立:显示钻井速度

      m_pThread =
AfxBeginThread
(ThreadFunc3,&m_ctrlProgress);

}

//暂时搁置的/开端

void
CMultThreadComm2Dlg
::OnBnClickedButton1()

{

      // TODO: 在在这里添加控制告诉处置顺序法典

      CString
szTitle
;

      GetDlgItemText(IDC_BUTTON1,szTitle);

      if (szTitle ==
暂时搁置的”)

      {//暂时搁置的

           g_bRun =
false
;

           SetDlgItemText(IDC_BUTTON1,开端”);

      }

      else

      {//开端

           g_bRun =
true
;

           OnStart();

           SetDlgItemText(IDC_BUTTON1,暂时搁置的”);

      }

}

//线程履行功用:实时显示流畅工夫

DWORD
WINAPI
ThreadFunc1(拉普拉斯lpParam)

{

      HWND *hWnd = (HWND*)lpParam;

    //CWnd *pWnd = AfxGetApp()->m_pMainWnd;//当不注意参量经过时,可以勤勉API造成

      CWnd *pWnd =
CWnd::FromHandle(*hWnd);

      char
tmpbuf
[128] ={”0”};

      time_t
t
;

      while(g_bRun)

      {

           t =
time
(NULL);

       strftime(tmpbuf,128,“%Y-%m-%d%a %I:%M:%S %p”,localtime(&t));

          pWnd->SetWindowText(tmpbuf);

          Sleep(500); 

      }

      return 0;

}

//线程履行功用:随机用胶版印刷

void
ThreadFunc2
(void *pArg)

{

      threadInfo *threadinfo= (threadInfo*)pArg;

      CWnd *pWnd =
CWnd::FromHandle(threadinfo->hWnd);

      CDC *pDC =
pWnd->GetDC();

      CPen
pen
(PS_SOLID,2,threadinfo->clrPen);

      pDC->SelectObject(&pen);

      pDC->SetROP2(R2_NOTXORPEN);

      while(g_bRun)

      {

           POINT
StartPos
= GetRandPoint();

           POINT
EndPos
= GetRandPoint();

           //

           CString
str
;

      str.Format(“%d,%d : %d,%d\n”,StartPos.x,StartPos.y,EndPos.x,EndPos.y);

           TRACE(str);

           pDC->MoveTo(StartPos);

           pDC->LineTo(EndPos);

           Sleep(100);

           pDC->MoveTo(StartPos);

           pDC->LineTo(EndPos);

           Sleep(100);

      }

      DeleteObject(pDC);

}

//线程履行功用:显示钻井速度

UINT
ThreadFunc3
(拉普拉斯lpParam)

{

      CProgressCtrl *pProgress= (CProgressCtrl*)lpParam;

      while(g_bRun)

      {

           pProgress->StepIt();

           Sleep(500); 

      }

      return 0;

}

//获取随机点

POINT
GetRandPoint
()

{

      POINT
Point
;

      Point.x =
rand()%439;

      Point.y =
rand()%208;

    return
Point
;

}

运转胜利:

工程源下载地址:

 

欢送大师修正并改良。。

参与理睬事项:

(1)   理睬三种线程的成立方式此外它们各自的线程重大聚会的体式每种典型的酬报都是变化多的的)。

(2)   理睬三种参量的交付:单一的参量、多参量(和解体),复合参量(类)。

(3)   勤勉参量交付榜样暂时搁置的线程间的通信仅仅是勤勉从线程到隶属线程的通信。

(4)   不觉悟大师看出该顺序的独一BUG不注意(大师可以下载工程源码,编制并运转,这可以很完全地地找到。。),执意线程二的随机用胶版印刷线程,含义是随机用胶版印刷并卸下,话虽这样说手术查明第一件商品线从未被移除。,为什么看一眼各位的大脑,你觉悟你可以留言,人文学科一齐努力议论!

4.音讯交付榜样

在Windows顺序设计中,敷用药的每个线程都有本人的音讯队列。,平均的任务线程都不的不规则的事物。,左右一来,它使得经过音讯在线程经过使转移教训发生轻易。。笔者可以在独一线程的履行重大聚会中向另独一线程发送自限制的音讯来成功通信的客观的。线程经过使运行体系向另一线程发送音讯。。勤勉Windows使运行体系的音讯驾驶机制,当线程发送音讯时,使运行体系率先接纳音讯。,于是将音讯转发到目的线程。,接纳音讯的线程必需早已成立了音讯以环连结。。这种方式可以造成必然的线程经过的通信。,因而这是一种每件东西遍及和遍及的方式。。

该体系还开价了在T经过发送音讯的特意功用。:PostThreadMessage()。用户率先限制用户音讯,在独一线程恳求中PostThreadMessage()重大聚会,音讯接纳线程呼应音讯。,普通和经用的孩童回应经文处置。仅音讯计划ON_THREAD_MESSAGE而缺陷ON_MESSAGE

万一线程具有整队,还可以勤勉普通音讯发送功用。PostMessage()和SendMessage()这两个功用。理睬二者经过的不符合,PostMessage它是独一异步重大聚会。,恳求后,重大聚会直接地重提,而SendMessage它是独一使工夫互相一致功用。,在重提垄断期待呼应的音讯呼应走完。。

发生着的PostThreadMessage()、PostMessage()和SendMessage参与重大聚会绍介,请参阅MSDN,在这里没什么可吃的。

在附近PostThreadMessage()的用法:

率先限制用户音讯,如:

#define WM_THREADMSG  WMUSER+100

对需求发送音讯的线程的恳求PostThreadMessage()重大聚会,如:

::PostThreadMessage(idThread,WM_THREADMSG,parm1, parm2);

或许

m_pThread->PostThreadMessage(WM_THREADMSG,parm1, parm2); 

流行: idThread接纳音讯线程的ID,parm1, parm2要交付的参量,m_pThread音讯同意线程交给。

在接纳音讯线程中(或在音讯处置线程中),首率先限制音讯呼应重大聚会,如:

afx_msgvoidOnThreadMessage(WPARAMwParam,LPARAMlParam);

于是将音讯计划添加到音讯计划表中。,如:

ON_THREAD_MESSAGE(WM_THREADMSG,OnThreadMessage)

上个,造成音讯功用,如:

//显示音讯处置功用

void
XXXXThread
::OnThreadMessage(WPARAMwParam,LPARAMlParam)

{

      ;//音讯处置

}

/////////////////////////////////////////////////////////////////////////////////

在附近PostMessage()/SendMessage()的用法:和上面的几乎,轻微地变化多的。

率先也率先限制用户音讯,如:

#define WM_THREADMSG  WMUSER+100

对需求发送音讯的线程的恳求PostMessage()/SendMessage()重大聚会,如:

::PostMessage(hWnd, WM_THREADMSG, parm1, parm2);//发送音讯

或许

PWnd->PostMessage(WM_THREADMSG, parm1, parm2);

或许

::SendMessage(hWnd, WM_THREADMSG, parm1, parm2);//发送音讯

或许

PWnd->SendMessage(WM_THREADMSG, parm1, parm2);

流行: hWnd接纳音讯的窗口句柄,parm1, parm2要交付的参量,pWnd音讯同意窗口交给。

在接纳音讯线程中(或在音讯处置线程中),首率先限制音讯呼应重大聚会,如:

afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);

于是将音讯计划添加到音讯计划表中。,如:

ON_MESSAGE(WM_THREADMSG, OnMyMessage)

上个,造成音讯功用,如:

//音讯处置重大聚会

LRESULT
XXXXWnd
::OnMyMessage(WPARAMwParam,LPARAMlParam)

{

      ;//音讯处置

return 0;

}

加盖于演示

同样情况次要用于计算无符号整数的积聚。,并勤勉独立的线程计算积聚。,成立另独一用户界面线程来显示积聚钻井速度,它关涉多个线程经过的通信。,该示例次要用于音讯的方式。,并联合收割机早已绍介的两种通信方式,有点具有声明与努力的花费。

次要源法典:

主线头纵列:

DWORD
WINAPI
ThreadFunc(拉普拉斯lpParam);//线程重大聚会

protected:

HANDLE
m_hThread
;//线程句柄

CProgressThread *m_pThread;//用户界面线程句柄

DWORD 
m_nThreadID
;//线程ID

主线程造成纵列:

//开端计算

void
CMultThreadComm3Dlg
::OnBnClickedButton1()

{

    // TODO: 在在这里添加控制告诉处置顺序法典

    UpdateData(TRUE);//补充知识

    g_bStop =
false
; //为出一套新题

    m_hThread =
CreateThread
(NULL,0,ThreadFunc,&m_nRange,0,NULL);//成立计算线程

    GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);//反复计算的警

    SetDlgItemText(IDC_STATIC_RESULT,在计算中……);

}

//总算显示:两种总算:,不变的,,半途塞住

LRESULT
CMultThreadComm3Dlg
::OnResult(WPARAMwParam,LPARAMlParam)

{

    if (wParam == 1)

    {//半途塞住

       SetDlgItemText(IDC_STATIC_RESULT,已使靠近!”);

    }

    else

    {//不变的完毕

       SetDlgItemInt(IDC_STATIC_RESULT,lParam);

    }

    GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);//启用下独一计算装有钮扣

    CloseHandle(m_hThread);//使靠近航班统治手段,一定要使靠近它

    return 0;

}

//线程履行功用:计算

DWORD
WINAPI
ThreadFunc(拉普拉斯lpParam)

{

    UINT *pRange =(UINT*)lpParam;//获取参量值

   long
nResult
= 0L;//计算总算值

    bool
bStop
= false;//半途打手势倘若暂时搁置的

    CProgressThread *m_pThread= (CProgressThread*)AfxBeginThread(RUNTIME_CLASS(CProgressThread));//成立显示处理

    m_pThread->PostThreadMessage(WM_PROGRESS,0,*pRange);//交付参量,钻井速度条的审视

    for(inti=0;i<=*pRange;i++)//开端计算

    {

       if (g_bStop)

       {//中道而弃

           bStop =
true
;

           break;//脱离以环连结

       }

       nResult +=
i
;

       m_pThread->PostThreadMessage(WM_PROGRESS,1,i);//钻井速度

       Sleep(10);//为了声明胜利,特别推延

    }

    //走完

    ::PostMessage(AfxGetApp()->m_pMainWnd->m_hWnd,WM_RESULT,bStop,nResult);//显示总算

    m_pThread->PostThreadMessage(WM_PROGRESS,2,0);//走完钻井速度

    return 0;

}

积聚线程头纵列:

CProgressDlg *m_pProgressDlg;//钻井速度条对话框

unsigned
int
m_nRange;//钻井速度条的审视

积聚线程造成纵列:

BOOL
CProgressThread
::InitInstance()

{

    // TODO: 在在这里履行必然的线程逐一线程设定初值

    //成立非榜样钻井速度显示对话框

    m_pProgressDlg =
new
CProgressDlg();

    m_pProgressDlg->Create(IDD_DIALOG1);

    m_pProgressDlg->ShowWindow(SW_SHOW);

    return
TRUE
;

}

BEGIN_MESSAGE_MAP(CProgressThread,
CWinThread)

    ON_THREAD_MESSAGE(WM_PROGRESS, &CProgressThread::OnThreadMsg)

END_MESSAGE_MAP()

// CProgressThread 音讯处置顺序

//线程音讯处置功用

void
CProgressThread
::OnThreadMsg(WPARAMwParam,LPARAMlParam)

{

    if (wParam == 0)

    {//设定初值钻井速度条

       m_nRange =
lParam
;

       m_pProgressDlg->m_ProgressCtrl.SetRange(0,lParam);

    }

    else
if
(wParam == 1)

    {//显示钻井速度

       m_pProgressDlg->m_ProgressCtrl.SetPos(lParam);//显示钻井速度

       CString
str
;

       str.Format(“%d%%”,int((float)lParam/m_nRange*100));

       m_pProgressDlg->m_stValue.SetWindowText(str);//显示比例

       str.Format(计算与处置,请稍等。 %d/%d        cbNotes”,lParam,m_nRange);//显示实时电流使运行

       m_pProgressDlg->SetWindowText(str);

    }

    else

    {//走完,脱离钻井速度条

       m_pProgressDlg->CloseDlg();//完毕票据的限期对话框

       AfxEndThread(0);//堵塞线程,也可以勤勉。PoxQuestMead(0)。

    }

}

钻井速度栏对话框类

//体系音讯处置

void
CProgressDlg
::OnSysCommand(UINTnID, LPARAMlParam)

{

    // TODO: 添加音讯处置顺序法典或恳求默许值

    if (nID ==
SC_CLOSE)//使靠近

    {//截取使靠近装有钮扣音讯

       if (AfxMessageBox(你想堵塞同样计算吗?,MB_YESNO|MB_APPLMODAL|MB_ICONQUESTION|MB_DEFBUTTON2)==IDYES)

       {

           g_bStop =
true
;//半途偿还,完毕计算线程。

       }

       return;

    }

    CDialog::OnSysCommand(nID,
lParam);

}

//使靠近窗口

void
CProgressDlg
::CloseDlg(void)

{

    OnCancel();

}

//偿还装货于:理睬非榜样对话框的脱离

void
CProgressDlg
::OnCancel()

{

    // TODO: 在在这里添加特别法典或恳求基类

   DestroyWindow();//

    //CDialog::OnCancel();

}

void
CProgressDlg
::PostNcDestroy()

{

    // TODO: 在在这里添加特别法典或恳求基类

    CDialog::PostNcDestroy();

    delete
this
;

}

运转总算:

工程源下载地址:

欢送大师修正并改良。。

参与理睬事项:

(1)理睬线程音讯的计划:

ON_THREAD_MESSAGE(WM_PROGRESS, &CProgressThread::OnThreadMsg)

与普通的窗口音讯计划变化多的,不要犯里面的。。

(2)理睬用户界面线程的脱离,计算完毕后,默记完毕线程。,有一种特别的功用:

AfxEndThread(0),也可以勤勉。PostQuitMessage(0)。这两种方式有点有价证券。。不要男仆力暂时搁置的线程。,要不然,会涌现出人意料的的成绩。。

(3)加盖于还造成了履行处理的处置方式。,采取全程变量

把持计算线程半途脱离的方式,根据我所持的论点这是一种反而更的把持方式。。我开端采取力暂时搁置的的方式会涌现音讯延后的景象(执意在脱离装有钮扣的处置重大聚会里向主线程发送音讯postmessage),不注意说辞这样的做。,有兴趣的情人可以尝试如此等等的违世方式暂时搁置的议论和看重。

(4)理睬非榜样对话框脱离的处置方式,从榜样对话框中脱离是差的。。

(5)勤勉CreateThread()重大聚会成立线程将重提线程句柄。,经过同样句柄,您可以把持和使运行线程。,当您不勤勉它时,您可以在成立线程后使靠近句柄。,有一种特别的功用CloseHandle()。使靠近句柄并代表使靠近线程,但是你不克不及把持里面的线(譬如),提早完毕,改观优先考虑的事等。。线程完毕后,体系将主动清算线程资源。,但它将不会主动使靠近统治手段。,因而默记在线程完毕后使靠近句柄。,你可能会问你为什么这样的烦乱,你需求使靠近手掌。,由于统治手段(统治手段)是内核反对,内核反对的支配是使运行体系的支配。,详细来说,可以检查互相牵连教训,我缺陷长的。

5。线程使工夫互相一致方式

还可以经过线程使工夫互相一致来造成线程间通信。譬如,有两个线程,线程A研究知识,线程B读取线程A预备的知识并履行必然的使运行。。这种制约下,线程A最适当的在线程A研究知识时读取。,但是在线程B读取知识后来的,线程才干持续研究知识。,这两个线程需求彼此使工夫互相一致通信。。线程使工夫互相一致的方式和把持是写多线索。小瘤与接触,方式也更多。,在这里不注意详细的解说和示例演示。,详细内容将在以下文字中绍介。,请持续关怀我的补充,致谢。

===========================================

重版请表明出处,致谢。

===========================================

发表评论

电子邮件地址不会被公开。 必填项已用*标注