MFC的工作者线程示例[张]
初始状态
四个线程先后开始运行,如图,会更新列表控件中的1234行的第2栏的值(第0行忽略)
先点第一个线程的按钮开始,然后点开始全部服务,实际上第一个线程函数被运行了两次,后三个线程只运行一次。
代码段:
class threadStruct
{
public:
int wm;
int iStopThread;
public:
threadStruct();
~threadStruct();
};
class CServerDlg : public CDialog
{
// Construction
public:
CWinThread* pThread1,*pThread2,*pThread3,*pThread4;
int iStopThread1,iStopThread2,iStopThread3,iStopThread4;
threadStruct thdStruct[5];
=============
BOOL CServerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//设置风格
LONG lStyle;
lStyle = GetWindowLong(m_listServerThread.m_hWnd, GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(m_listServerThread.m_hWnd, GWL_STYLE, lStyle);//设置style
DWORD dwStyle = m_listServerThread.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
//dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件
m_listServerThread.SetExtendedStyle(dwStyle); //设置扩展风格
m_listServerThread.InsertColumn( 0, "ID", LVCFMT_LEFT, 50 );//插入列,将宽度设置成0,在外观上就看不到此列,用来存放会员号
m_listServerThread.InsertColumn( 1, "线程", LVCFMT_LEFT, 80 );
m_listServerThread.InsertColumn( 2, "值", LVCFMT_LEFT, 80 );
m_listServerThread.InsertColumn( 3, "-", LVCFMT_LEFT, 60 );
m_listServerThread.InsertColumn( 4, "-", LVCFMT_LEFT, 60 );
m_listServerThread.InsertColumn( 5, "-", LVCFMT_LEFT, 160 );
m_listServerThread.InsertColumn( 6, "-", LVCFMT_LEFT, 160 );
m_listServerThread.InsertItem(0, 0);//插入行
m_listServerThread.SetItemText(0, 1, "0");
m_listServerThread.SetItemText(0, 2, "x");//设置数据
m_listServerThread.SetItemText(0, 3, "50");
m_listServerThread.SetItemText(0, 4, "5");
m_listServerThread.SetItemText(0, 5, "2010-12-1");
m_listServerThread.SetItemText(0, 6, "2010-12-1");
m_listServerThread.InsertItem(1, 0);//插入行
m_listServerThread.SetItemText(1, 1, "1");
m_listServerThread.SetItemText(1, 2, "x");//设置数据
m_listServerThread.SetItemText(1, 3, "50");
m_listServerThread.SetItemText(1, 4, "5");
m_listServerThread.SetItemText(1, 5, "2010-12-1");
m_listServerThread.SetItemText(1, 6, "2010-12-1");
m_listServerThread.InsertItem(2, 0);//插入行
m_listServerThread.SetItemText(2, 1, "2");
m_listServerThread.SetItemText(2, 2, "x");//设置数据
m_listServerThread.SetItemText(2, 3, "50");
m_listServerThread.SetItemText(2, 4, "5");
m_listServerThread.SetItemText(2, 5, "2010-12-1");
m_listServerThread.SetItemText(2, 6, "2010-12-1");
m_listServerThread.InsertItem(3, 0);//插入行
m_listServerThread.SetItemText(3, 1, "3");
m_listServerThread.SetItemText(3, 2, "x");//设置数据
m_listServerThread.SetItemText(3, 3, "50");
m_listServerThread.SetItemText(3, 4, "5");
m_listServerThread.SetItemText(3, 5, "2010-12-1");
m_listServerThread.SetItemText(3, 6, "2010-12-1");
m_listServerThread.InsertItem(4, 0);//插入行
m_listServerThread.SetItemText(4, 1, "4");
m_listServerThread.SetItemText(4, 2, "x");//设置数据
m_listServerThread.SetItemText(4, 3, "50");
m_listServerThread.SetItemText(4, 4, "5");
m_listServerThread.SetItemText(4, 5, "2010-12-1");
m_listServerThread.SetItemText(4, 6, "2010-12-1");
(this->GetDlgItem(IDC_BUTTON6))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON7))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON8))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON9))->EnableWindow(false);
SetTimer(1,1000,NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
================
UINT ThreadFunc1(LPVOID lpParam)
{
threadStruct* pwwm=(threadStruct*)lpParam;
int bm;
bm=1;
while (bm)
{
if (pwwm->iStopThread==1 )
{
bm=0;
}
(pwwm->wm)++;
if ((pwwm->wm) > 99)
{
(pwwm->wm)=0;
}
Sleep(2000);
}
return 0;
}
void CServerDlg::OnBtnStartserver()
{
// TODO: Add your control notification handler code here
OnButton1();
OnButton2();
OnButton3();
OnButton4();
}
void CServerDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch (nIDEvent)
{
case 1:
{
//更新列表框
CString str1;
str1.Format("%d",thdStruct[1].wm);
m_listServerThread.SetItemText(1,2,TEXT(str1));//将该行的列值修改为1
m_listServerThread.Update(1);
str1.Format("%d",thdStruct[2].wm);
m_listServerThread.SetItemText(2,2,TEXT(str1));//将该行的列值修改为1
m_listServerThread.Update(1);
str1.Format("%d",thdStruct[3].wm);
m_listServerThread.SetItemText(3,2,TEXT(str1));//将该行的列值修改为1
m_listServerThread.Update(1);
str1.Format("%d",thdStruct[4].wm);
m_listServerThread.SetItemText(4,2,TEXT(str1));//将该行的列值修改为1
m_listServerThread.Update(1);
}
case 2:
{
}
};
CDialog::OnTimer(nIDEvent);
}
void CServerDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
KillTimer(1);
}
void CServerDlg::OnBtnStopserver()
{
// TODO: Add your control notification handler code here
OnButton6();
OnButton7();
OnButton8();
}
void CServerDlg::OnButton1() //开始线程
{
// TODO: Add your control notification handler code here
pThread1=AfxBeginThread(ThreadFunc1,&thdStruct[1]);
(this->GetDlgItem(IDC_BUTTON1))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON6))->EnableWindow(true);
}
void CServerDlg::OnButton2() //开始线程
{
// TODO: Add your control notification handler code here
pThread2=AfxBeginThread(ThreadFunc1,&thdStruct[2]);
(this->GetDlgItem(IDC_BUTTON2))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON7))->EnableWindow(true);
}
void CServerDlg::OnButton3() //开始线程
{
// TODO: Add your control notification handler code here
pThread3=AfxBeginThread(ThreadFunc1,&thdStruct[3]); //在MFC中,一般由全局函数AfxBeginThread来创建并初始化一个线程的运行
//创建工作者线程,程序员不必从CWinThread派生新的线程类,只需要提供一个线程入口,也就是一个函数地址就可以了。
//在工作者线程被启动后会转入该函数,并且函数退出时线程就会结束。
//线程函数的固定形式是,UINT Function(LPVOID pParam)
(this->GetDlgItem(IDC_BUTTON3))->EnableWindow(false); //CWinThread* AFXAPI AfxBeginThread(......)
(this->GetDlgItem(IDC_BUTTON8))->EnableWindow(true);
}
void CServerDlg::OnButton4() //开始线程
{
// TODO: Add your control notification handler code here
pThread4=AfxBeginThread(ThreadFunc1,&thdStruct[4]);
(this->GetDlgItem(IDC_BUTTON4))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON9))->EnableWindow(true);
}
void CServerDlg::OnButton6() //停止线程,通过将传给线程的类对象的一个成员设为1来达到,使线程函数中的循环条件失效而退出线程函数
{
// TODO: Add your control notification handler code here
thdStruct[1].iStopThread=1;
(this->GetDlgItem(IDC_BUTTON6))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON1))->EnableWindow(true);
}
void CServerDlg::OnButton7() //停止线程
{
// TODO: Add your control notification handler code here
thdStruct[2].iStopThread=1;
(this->GetDlgItem(IDC_BUTTON7))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON2))->EnableWindow(true);
}
void CServerDlg::OnButton8() //停止线程
{
// TODO: Add your control notification handler code here
thdStruct[3].iStopThread=1;
(this->GetDlgItem(IDC_BUTTON8))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON3))->EnableWindow(true);
}
void CServerDlg::OnButton9() //停止线程
{
// TODO: Add your control notification handler code here
thdStruct[4].iStopThread=1;
(this->GetDlgItem(IDC_BUTTON9))->EnableWindow(false);
(this->GetDlgItem(IDC_BUTTON4))->EnableWindow(true);
}
本示例为本人设计,变量命名不规范,主要是想试验一下MFC工作者线程的运行情况。
把书本上最关键的几句摘录如下:
工作者线程的创建,程序员不必从CWinThread派生新的线程类(用户界面线程需派生),只需要提供一个线程入口中,也就是一个函数地址即可,在工作者线程被启动后会转入该函数,并且函数退出时线程就会结束。该线程函数的固定形式为:UINT Function(LPVOID pParam)
注意线程函数的参数为LPVOID,可以根据参数的类型进行强制转换,然后就可以通过强制转换得到的指针来访问传来的参数的内存空间。可以传入类对象或结构对象,或者内置数据类型。
在本例中,单击开始按钮,可开始一个线程,如果对同一按钮多次单击(每次单击后不禁用按钮,或者不同的按钮重复调用一个函数),会导致意外的开始新的线程。在本例中,每次递增的值可能是1,2,或4,就反应了这一点。
要退出一个工作者线程,需要强制退出线程函数。
自定义的类对象中的第二个变量,就是用来强制中止线程而定义的。