线程间的同步概述
线程间的同步概述1.前言前面几篇文章着重介绍了多线程的三种创建方式及多线程间的4种通信方式,并采用大量的实例演示,相信大家对线程的创建和使用有了一定的了解。若还不了解请复习下前面的文章,多动手写代码和调试,光看不练,假把式。今天先请大家看看下面一个多线程程序,操作很简单,就是创建9个线程,并输出相应的线程编号(即报数)。主要代码如下:[cpp]//声明线程处理函数<strong><span style="color:#ff0000;">unsigned __stdcall</span></strong>ThreadFunc( void* pArguments);//工作线程函数HANDLE m_handle[9];//线程句柄列表CListBox m_List; //数据列表控件/////////////////////////////////////////////////int g_nCount= 0;//这个是<strong><span style="color:#ff0000;">全局变量</span></strong>,用于线程报数(计数)//演示开始:创建线程void CThreadProblem1Dlg::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);m_List.ResetContent();//清空列表g_nCount = 0; //重置报数,SetDlgItemInt(IDC_EDIT_NUM,++m_nNum); //显示操作的次数//创建多线程for (int i=0;i<9;i++){m_handle[i] = (HANDLE)<strong><span style="color:#ff0000;">_beginthreadex</span></strong>(NULL,0, ThreadFunc,&m_List,0, NULL);}//WaitForMultipleObjects(10, handle, TRUE, INFINITE); //在此处等待退出,将发现程序假死了。所以采用线程的方式等待_beginthreadex(NULL,0, WaitThread,<strong><span style="color:#ff0000;">this</span></strong>, 0, NULL); //等待上述的个线程都退出}//工作线程函数unsigned __stdcall ThreadFunc(void* pArguments){Sleep(100);//相关处理g_nCount++; //计数加CListBox *pList= (CListBox*)pArguments;CString str;str.Format(" 子线程ID号为%4d 报数为:%d",GetCurrentThreadId(),g_nCount);pList->AddString(str);//输出Sleep(100);//相关处理return 0;}//线程函数:等待个演示线程都退出再使能开始按钮unsigned __stdcall WaitThread(void* pArguments){CThreadProblem1Dlg *pMainDlg= (CThreadProblem1Dlg *)pArguments;<strong><span style="color:#ff0000;">WaitForMultipleObjects</span></strong>(9,pMainDlg->m_handle,TRUE, INFINITE); //等待所有线程都结束EnableWindow(GetDlgItem(AfxGetApp()->m_pMainWnd->m_hWnd,IDC_BUTTON1),TRUE);//使能开始按钮return 0;}当运行一次OnBnClickedButton1()函数,将显示下面的结果:你一看,没错呀,就应该是这样的,没有错呀!多运行几次也是这样的。但我要肯定的告诉你,上面的程序是有严重的问题,而运行结果也欺骗了你。正是运行结果大大蒙骗了你的理智和大脑。你发现问题了吗?(提示:不是报数顺序的问题)www.zzzyk.com正是该错误有隐蔽性,你很难从结果中发现问题,除非你运气特别好,一运行就能重现问题,但作为程序员,你决不能仅靠运气,不可能你每次的运气都这么好。多运行几次上面的程序,你有可能发现问题,现在我把该程序改进下,使其具有自动识别错误的智能,你一眼就能发现问题的。改进点:添加结果检测功能,若正常,其线程的报数应该为1-9,有可能顺序有变,但总和为45=1+2+3+4+5+6+7+8+9。程序将一直循环到程序退出。若不等于45就退出循环,表示有问题,即让程序一直运行,直到有错误为止。前面的OnBnClickedButton1()函数和ThreadFunc()函数保存不变,WaitThread()函数添加一个判断语句,改进程序如下:[cpp]//线程函数:等待个演示线程都退出再使能开始按钮unsigned __stdcall WaitThread(void* pArguments){CThreadProblem1Dlg *pMainDlg= (CThreadProblem1Dlg *)pArguments;WaitForMultipleObjects(9, pMainDlg->m_handle, TRUE,INFINITE); //等待所有线程都结束EnableWindow(GetDlgItem(AfxGetApp()->m_pMainWnd->m_hWnd,IDC_BUTTON1),TRUE);//使能开始按钮<span style="color:#ff0000;"><strong> if(pMainDlg->m_bAuto&& !pMainDlg->IsError()){//若自动使能,则继续下易做图作pMainDlg->OnBnClickedButton1();}</strong></span>return 0;}//添加IsError()函数,用以判断结果是否正确。// 自动判断每次运行结果是否正确bool CThreadProblem1Dlg::IsError(void){int nValue[9]={0};int nResult = 0;CString szText;for(int i=0;i<9;i++){//得到各个线程的报数m_List.GetText(i,szText);szText = szText.Right(1);nValue[i] = atoi(szText);nResult += nValue[i];}//判断是否有相同的值出现if (nResult != <span style="color:#ff0000;"><strong>45</strong></span>){//有错误return true;}return false;}再运行上面的程序,选中“自动判断”,程序将很快不停的运行,但很快将又停下来,运行结果如下图所示,有可能你的结果和我的不一样,但类型差不多的。现在你发现问题了吗?对了,报数出现相同数了(见上图出现两个“2”)。你可能要问,怎么会这样呢?这就是多线程最容易出现的问题,也是多线程编程的难点和核心。再说说上面程序,创建了9个线程,这9个线程是同时运行的(即并行运行),它们都要修改变量全局g_nCount(g_nCount++;),就有可能两个或多个线程同时读取到g_nCount,而当前的g_nCount已经被其它线程修改,即输出的不是线程当前的值。这和单线程的顺序执行是有很大不同的。那有什么方法解决上面的问题吗?当然有,这就是在江湖中大名鼎鼎的线程同步技术,而且系统提供了多种线程同步的技术/方法。2.什么是同补充:软件开发 , C++ ,
上一个:Dividing 03多重背包问题
下一个:判断欧拉回路
- 更多C/C++疑问解答:
- 关于c++的cout输出的问题。
- 在学校里学过C和C++,不过学的很一般,现在自学C#,会不会很难?
- 全国计算机二级C语言笔试题
- 已知某树有2个2度结点,3个3度结点,4个4度结点,问有几个叶子结点?
- c++数据结构内部排序问题,整数排序
- 2012九月计算机二级C语言全国题库,,急求急求
- 如果assert只有一个字符串作为参数,是什么意思呢?
- C语言中,哪些运算符具有左结合性,哪些具有右结合性,帮忙总结下,谢谢了!
- 为什么用结构体编写的程序输入是,0输不出来啊~~~
- 将IEEE—754的十六进制转化为十进制浮点类型,用C或C++都行,多谢各位大侠啊,非常感谢!
- 为什么这个程序求不出公式?
- 这个链表倒置的算法请大家分析下
- c语言函数库调用
- C语言unsigned int纠错
- C语言快排求解啊