📄 csdn_文档中心_线程通信初探.htm
字号:
<TBODY>
<TR bgColor=#ffffff>
<TD align=middle height=10 width=50></TD>
<TD align=right><A href="http://www.csdn.net/">CSDN</A> - <A
href="http://www.csdn.net/develop/">文档中心</A> - <FONT
color=#003399>Visual C++</FONT> </TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399 height=10><FONT
color=#ffffff>标题</FONT></TD>
<TD><B> 线程通信初探</B> panda_w(原作)
</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399><FONT color=#ffffff>关键字</FONT></TD>
<TD width=500> 线程通信初探</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR></TBODY></TABLE><!--文章说明信息结束//-->
<TABLE border=0 width=600>
<TBODY>
<TR>
<TD align=left><BR>
进程是运行中的程序,有独立的内存,文件句柄和其它的系统资源,一个独立的进程可以包含多条执行路径,即线程。一个函数可以被多个线程访问,多个线程可以访问同一个全局变量。<BR>
Windows提供两种线程,用户界面线程和辅助线程。用户界面线程有窗口,因此有自己的消息循环,辅助线程没有窗口,不需要处理消息。但是辅助线程非常有用而且很容易编程,比如程序在某个运行时间要完成多个(很笨重的)任务时,显然,辅助线程的使用会使程序的运行效率大大的提高。但是,线程间的通信是一个必须解决的问题。<BR>
下面我们就来讨论一下线程间的通信的问题:<BR>
一.线程的管理<BR>
1.线程的启动:<BR>
在使用辅助线程时,我们必须为线程写一个全局函数,它的返回值必须为
UINT类型,而且必须有LPVOID类型的参数,启动线程调用下面的函数:<BR>
CWinThread*
pThread=AfxBeginThread(<BR>
AFX_THREADPPOC
ThreadProc,<BR>
LPVOID
pParam,<BR>
int
nPriority,<BR>
UINT
nStackSize,<BR>
DWORD
dwCreateFlags,<BR>
LPSECURITY_ATTRIBUTES lpSecurityAttrs);<BR>
全局函数必须定义为 UINT ThreadProc(LPVOID pParam);<BR>
AfxBeginThread会立即返回一个指向新创建的线程对象的指针,用来管理线
程,包括挂起和恢复线程的运行,但是线程对象没有成员函数来中止线程的运
行。AfxBeginThread的第二个参数是一个32位的值,用来传给全局函数;第三
个参数用来设定线程的优先级;而第四和第六个参数用来指定线程堆栈大小和
安全性,一般采用默认值0;第五个参数用来设定创建线程对象的方式,0为立
即执行,CREATE_SUSPEND为线程通过ResumeThread后才执行。<BR>
而线程优先级的设置和获得可以通过下面的两个函数来实现:<BR>
pThread->SetThreadPriority(THREAD_PRIORITY_ABOVE_NOMAL);和<BR>
int nPriority=pThread->GetThreadPriority();<BR>
2.线程的中止:<BR>
可以调用MFC的AfxEndThread函数;<BR>
3.检查线程是否结束:<BR>
调用API函数GetExitCodeThread,<BR>
DWORD ExitCode
;<BR>
::GetExitCodeThread(pThread->m_hThread,&ExitCode
);<BR>
if(ExitCode==STILL_ACTIVE)<BR>
//运行中<BR>
else //线程已经中止<BR>
二.主线程和辅助线程的通信<BR>
主线程和辅助线程间的通信方式有很多种,最简单的就是利用全局变量。
这里利用消息通信是行不通的,因为辅助线程没有消息循环,不能够利用
Windows消息。<BR>
下面我们用一个例子来说明。在例子中,我们写一个非常笨的函数,如实
现500*3000*3000的加法数据处理函数Add(int nCount);<BR>
我们在对话框上放置Start、Cancel按钮和一个用来表示数据处理进度的进度条
。<BR>
1.利用全局变量来实现主线程和辅助线程的通信:<BR>
我们编写全局函数如下:<BR>
UINT ThreadProc(LPVOID
pParam)<BR>
{<BR>
nCount=0;//全局变量<BR>
while(nCount<500)<BR>
{<BR>
Add(nCount);<BR>
::InterlockedIncrement((long*)&ncount);<BR>
}<BR>
return 0;<BR>
}<BR>
函数InterlockIncrement阻塞其它的线程,当计数器递增时防止其它的线程访问nCount。<BR>
2.利用消息实现辅助线程和主线程的通信:<BR>
主线程有一个窗口,有消息循环,我们可以在调用AfxBeginThread时把窗口句柄传递给辅助线程,我们通过post方式传递消息,在函数退出时,给窗口发送一个消息。<BR>
重新编写线程函数如下:<BR>
int
nCount=0;<BR>
UINT ThreadProc(LPVOID
pParam)<BR>
{<BR>
while(nCount<500)<BR>
{<BR>
::InterlockedIncrement((long*)&ncount);<BR>
Add(nCount);<BR>
}<BR>
::PostMessage(<BR>
(HWND)pParam,<BR>
WM_THREADFINISHED,//用户自定义消息<BR>
0,0);<BR>
return
0;<BR>
}<BR>
编写OnStart函数:<BR>
void
CThreadDlg::OnStart()<BR>
{<BR>
m_nTimer=SetTimer(1,100,NULL);//0.1秒<BR>
ASSERT(m_nTimer!=0);<BR>
GetDlgItem(IDC_START)->EnableWindow(FALSE);<BR>
AfxBeginThread(ThreadProc,GetSafeHwnd(),THREAD_PROIRITY_NOMAL);<BR>
}<BR>
编辑OnCancel函数如下:<BR>
void
CThreadDlg::OnCancel()<BR>
{<BR>
if(nCount==0)<BR>
CDialog::OnCancel();<BR>
else
nCount=500;<BR>
}<BR>
处理OnThreadFinished函数<BR>
HRESULT CThreadDlg::OnThreadFinished(WPARAM wParam,LPARAM
lParam)<BR>
{<BR>
CDialog::OnOk();<BR>
return
0;<BR>
}<BR>
3.用事件使线程同步:<BR>
利用WaitForSingleObject函数<BR>
在stdafx.h中写入下面一行<BR> #include
<afxmt.h>//由于使用了事件<BR>
声明两个全局变量<BR>
CEvent m_start,m_kill;<BR>
在初始化函数中启动线程;<BR>
重新编写OnStart函数:<BR>
void
CThreadDlg::OnStart()<BR>
{<BR>
m_nTimer=SetTimer(1,100,NULL);//0.1秒<BR>
ASSERT(m_nTimer!=0);<BR>
GetDlgItem(IDC_START)->EnableWindow(FALSE);<BR>
m_start.SetEvent();<BR>
}
<BR>
重新编辑OnCancel函数如下:<BR>
void
CThreadDlg::OnCancel()<BR>
{<BR>
if(nCount==0)<BR>
m_start.SetEvent();<BR>
else
m_kill.SetEvent();<BR>
} <BR>
编写全局函数如下:<BR>
UINT ThreadProc(LPVOID
pParam)<BR>
{<BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -