8_MFC的进程和线程
MFC多线程控制进度条
MFC多线程控制进度条先看一下效果图..进度条的进度是创建一个新的线程控制,当单击"开始"按钮时,就创建一个线程,在这个线程中控制进度条的进度,这样就可以对窗口进行其他操作,要是没有创建一个新的线程控制进度,则整个程序需要等待进度条执行完后才能进行其他操作....对于进度条控件关联了一个控件变量m_speed CProgressCtrl m_speed;DDX_Control(pDX, IDC_PROGRESS1, m_speed);在头文件中声明线程函数static DWORD WINAPI ThreadSpeed(LPVOID lpParameter);这里需要注意我为什么将线程函数声明为静态函数,后面我会讲解声明这个句柄是用于接受创建线程时返回的句柄,可以使用这个句柄对线程控制,如挂起,唤醒以及终止等等操作HANDLE m_ThreadSpeed;声明的按钮函数,双击按钮由编译器自动生成的afx_msg void OnBnClickedButton2(); //"开始"按钮函数afx_msg void OnBnClickedButton1(); //"挂起"按钮函数afx_msg void OnBnClickedButton3(); //"唤醒"按钮函数afx_msg void OnBnClickedButton4(); //"终止"按钮函数在cpp文件中线程函数的实现[cpp] view plaincopyDWORD WINAPICSpeedDlg::ThreadSpeed(LPVOID lpParameter){ CProgressCtrl *Speed = (CProgressCtrl*)lpParameter; Speed->SetRange(0,100000); //设置进度条的范围for (int i = 0; i < 100000; i++){ Speed->SetPos(i); //进度条的位置} return 0; }"开始"按钮函数的实现[cpp] view plaincopyvoidCSpeedDlg::OnBnClickedButton2(){// TODO: 在此添加控件通知处理程序代码m_ThreadSpeed =CreateThread(0,0,ThreadSpeed,&m_speed,0,0); //创建线程}线程挂起时进度条停止前进,当线程唤醒时进度条继续前进,当线程终止时,进度条永远不会在前进,除非再次单击"开始"按钮创建新线程进度条从新开始[cpp] view plaincopy//挂起线程函数void CSpeedDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码SuspendThread(m_ThreadSpeed); //挂起线程函数,参数为线程句柄} //唤醒线程函数void CSpeedDlg::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码ResumeThread(m_ThreadSpeed); //唤醒挂起的线程}//终止线程函数void CSpeedDlg::OnBnClickedButton4() { // TODO: 在此添加控件通知处理程序代码TerminateThread(m_ThreadSpeed,0); //终止线程SendMessage(WM_CLOSE); //发送WM_CLOSE消息关闭窗口,退出程序} 这里我来谈谈为什么线程函数声明时为什么要定义成静态,如果不是静态函数则在CreateThread()函数中引用线程函数出错,看图片因为我定义的线程函数在类里,如果不是静态函数,调用时需要定义一个对象,有对象调用该函数,而我这里定义为静态函数使得这个函数不属于任何对象,可以直接调用,就可以解决上面图片里出的问题,如果线程函数定义为一个全局变量,也就是在类的外面定义,则不需要这样定义为静态函数,因为我这里把线程函数定义为了静态变量,而m_spend不是静态变量,它是进度控件的控件变量,定义为CProgressCtrl类的对象,我不知怎么来把它定义为静态的,如果直接static CProgressCtrlm_speed,这样的话会出错,这样m_speed不能在线程函数中使用,出现的错误是所以我的解决办法是让m_speed作为参数传给线程函数,然后在线程函数中定义一个CProgressCtrl类的指针类型对象来接受m_speed,不过这里要记得类型的强制转换,修改后正如上面线程函数实现代码一样版权声明:本文为博主原创文章,未经博主允许不得转载。
mfc创建线程的三种方法
mfc创建线程的三种方法在MFC编程中,线程的创建是一项常见的任务。
通过创建线程,我们可以在程序中实现并行处理和异步操作。
MFC提供了多种方式来创建线程。
本文将介绍MFC中创建线程的三种常用方法,以帮助读者更好地理解和应用多线程编程。
正文1. 使用CWinThread派生类MFC提供了CWinThread类,它是一个抽象基类,可以用来创建线程。
我们可以派生自CWinThread类并重写其Run()函数,然后通过调用AfxBeginThread()函数来启动线程。
下面是一个示例代码:```cppclass MyThread : public CWinThread{public:virtual BOOL InitInstance(){// 初始化线程return TRUE;}virtual int Run(){// 线程执行的代码return 0;}};// 在某个函数中创建并启动线程void CreateThreadUsingCWinThread(){MyThread* pThread = new MyThread();pThread->CreateThread();}```2. 使用CWinThread派生类的静态成员函数除了重写CWinThread派生类的Run()函数外,我们还可以使用该类提供的静态成员函数作为线程的入口点。
这种方法不需要明确地创建线程对象,而是直接使用类名调用静态成员函数。
下面是一个示例代码:```cppclass MyThread : public CWinThread{public:static UINT ThreadProc(LPVOID pParam){// 线程执行的代码return 0;}};// 在某个函数中创建并启动线程void CreateThreadUsingStaticFunction(){AfxBeginThread(MyThread::ThreadProc, nullptr);}```3. 使用普通函数作为线程的入口点除了使用CWinThread派生类,我们还可以直接使用普通函数作为线程的入口点。
mfc多线程编程 主线程等待子线程退出函数
MFC多线程编程 - 主线程等待子线程退出函数1.引言MFC(Microsoft Foundation Class)是微软提供的一套C++类库,用于快速开发Windows应用程序。
在实际开发中,多线程编程是一种常见的技术需求,用于解决程序中复杂的并发控制和逻辑处理问题。
本文将针对MFC多线程编程中主线程等待子线程退出函数的实现进行详细介绍。
2.多线程概述多线程编程是指在一个程序中同时运行多个独立的线程,每个线程可以执行不同的任务并且可以并发执行。
在MFC中,多线程编程可以通过CWinThread类或AfxBeginThread函数来实现。
在实际应用中,主线程通常会创建一个或多个子线程来完成耗时的任务,主线程需要等待所有子线程执行完毕后再继续执行其他操作。
3.主线程等待子线程退出函数的需求在实际开发中,主线程常常需要等待所有子线程执行完毕后再进行后续的操作,这就需要主线程等待子线程退出函数的支持。
在MFC中,主线程可以通过在子线程结束时调用WaitForSingleObject或WaitForMultipleObjects函数来实现等待子线程退出的功能。
4.主线程等待子线程退出函数的使用方法主线程等待子线程退出函数的使用方法一般分为以下几个步骤:4.1 创建子线程在MFC中,可以通过CWinThread类或AfxBeginThread函数来创建子线程,子线程可以执行需要的任务,并在任务执行完毕后调用ExitInstance函数结束线程。
4.2 处理线程退出通知在子线程执行完毕后,需要通知主线程线程已退出。
可以通过PostThreadMessage或SendMessage等方式向主线程发送线程退出消息。
4.3 主线程等待子线程退出主线程在收到线程退出消息后,可以调用WaitForSingleObject或WaitForMultipleObjects函数来等待所有子线程退出。
这些函数会使主线程阻塞,直到指定的线程对象被释放。
MFC程序的启动过程与相关函数的执行顺序
MFC程序的启动过程与相关函数的执行顺序1、创建Application object对象theApp程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp 对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数。
该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此,CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。
2、WinMain登场用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,哦!~ 原来她是被隐藏在MFC代码里面了。
当theApp配置完成后,WinMain 登场,慢!细看程序,并没连到WinMain函数的代码啊!这个我也不知道,MFC早已准备好并由链接器直接加到应用程序代码中了,原来她在APPMODUL.CPP里面,好,我们就认为当theApp配置完成后,程序就转到APPMODUL.CPP来了。
那执行什么呢?看看下面从APPMODUL.CPP摘出来的代码:extern "C" int WINAPI_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){// call shared/exported WinMainreturn AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);}_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。
_tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于WINMAIN.CPP第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){int nReturnCode = -1;CWinApp* pApp = AfxGetApp();AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);pApp->InitApplication();pApp->InitInstance()nReturnCode = pApp->Run();AfxWinTerm();return nReturnCode;}AfxGetApp()函数是取得CMyWinApp对象指针,故上面函数第6至8行相当于调用:CMyWinApp::InitApplication();CMyWinApp::InitInstance()CMyWinApp::Run();因而导致调用:CWinApp::InitApplication(); //因为 CMyWinApp 并没有改写 InitApplication CMyWinApp::InitInstance() //因为 CMyWinApp 改写了 InitInstanceCWinApp::Run(); //因为 CMyWinApp 并没有改写 Run用过SDK写程序的朋友,现在可能会发出会心的微笑。
mfc线程传递参数
在MFC(Microsoft Foundation Class)中,线程间传递参数可以通过多种方式实现。以下是一些常用的方法:
1.使用全局变量或静态变量:ห้องสมุดไป่ตู้
定义全局或静态变量,在线程函数中访问这些变量。
这种方法简单,但不推荐在多线程编程中使用全局变量,因为可能会导致竞态条件和不可预知的行为。
2.使用函数参数:
在创建线程时,将参数作为线程函数的参数传递。
这种方法适用于传递少量数据。
3.使用线程局部存储(Thread LocalStorage,TLS):
MFC提供了`AFX_TLS`宏来使用线程局部存储。
每个线程都有自己的数据副本,不会与其他线程共享。
4.使用队列(如消息队列、事件队列等):
创建一个队列来存储要传递的数据。
生产者线程将数据放入队列,消费者线程从队列中取出数据。
5.使用共享内存或内存映射文件:
创建一个共享的内存区域,线程间可以读写该区域的数据。
需要使用同步机制(如互斥量、临界区)来确保数据的一致性和线程安全。
6.使用MFC的CWinThread对象:
每个CWinThread对象都有一个与之关联的线程局部存储(TLS)。可以用来存储在线程特定的数据。
7.使用CObject的序列化:
如果参数是复杂类型(如CObject派生类),可以使用MFC的序列化机制将其写入到文件中,然后在线程函数中读取文件来获取参数。
8.使用MFC的消息映射机制:
使用消息映射可以在线程间传递消息和参数,但通常用于UI线程和其他工作线程之间的通信。
选择哪种方法取决于具体的应用场景和需求,例如数据的数量、类型以及线程间的通信模式。在多线程编程中,一定要注意线程安全和数据同步的问题。
MFC程序中消息以及函数的处理顺序简介
MFC程序中消息以及函数的处理顺序简介MFC应用程序中处理消息的顺序1.AfxWndProc()该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc2.AfxCallWndProc() 该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数3.WindowProc()该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数4.OnWndMsg()该函数的功能首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数,对于WM_NOTIFY消息调用OnNotify()消息响应函数。
任何被遗漏的消息将是一个窗口消息。
OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。
如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数5.OnCommand()该函数查看这是不是一个控件通知(lParam参数不为NULL,如果lParam参数为空的话,说明该消息不是控件通知),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果他不是一个控件通知(或者如果控件拒绝映射的消息)OnCommand()就会调用OnCmdMsg()函数6.OnCmdMsg()根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。
例如:如果拥有该窗口的类是一个框架类,则命令和通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数MFC应用程序创建窗口的过程1.PreCreateWindow()该函数是一个重载函数,在窗口被创建前,可以在该重载函数中改变创建参数(可以设置窗口风格等等)2.PreSubclassWindow() 这也是一个重载函数,允许首先子分类一个窗口3.OnGetMinMaxInfo()该函数为消息响应函数,响应的是WM_GETMINMAXINFO消息,允许设置窗口的最大或者最小尺寸4.OnNcCreate()该函数也是一个消息响应函数,响应WM_NCCREATE消息,发送消息以告诉窗口的客户区即将被创建5.OnNcCalcSize()该函数也是消息响应函数,响应WM_NCCALCSIZE消息,作用是允许改变窗口客户区大小6.OnCreate()该函数也是一个消息响应函数,响应WM_CREATE消息,发送消息告诉一个窗口已经被创建7.OnSize()该函数也是一个消息响应函数,响应WM_SIZE消息,发送该消息以告诉该窗口大小已经发生变化8.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息说明窗口在移动9.OnChildNotify()该函数为重载函数,作为部分消息映射被调用,告诉父窗口即将被告知一个窗口刚刚被创建MFC应用程序关闭窗口的顺序(非模态窗口)1.OnClose()消息响应函数,响应窗口的WM_CLOSE消息,当关闭按钮被单击的时候发送此消息2.OnDestroy()消息响应函数,响应窗口的WM_DESTROY消息,当一个窗口将被销毁时,发送此消息3.OnNcDestroy()消息响应函数,响应窗口的WM_NCDESTROY消息,当一个窗口被销毁后发送此消息4.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作,被CWnd调用MFC应用程序中打开模式对话框的函数调用顺序1.DoModal()重载函数,重载DoModal()成员函数2.PreSubclassWindow()重载函数,允许首先子分类一个窗口3.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建4.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化5.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息,以告诉窗口正在移动6.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息,以允许改变对话框中控件的字体7.OnInitDialog()消息响应函数,响应WM_INITDIALOG消息,发送此消息以允许初始化对话框中的控件,或者是创建新控件8.OnShowWindow()消息响应函数,响应WM_SHOWWINDOW消息,该函数被ShowWindow()函数调用9.OnCtlColor()消息响应函数,响应WM_CTLCOLOR消息,被父窗口发送已改变对话框或对话框上面控件的颜色10. OnChildNotify()重载函数,作为WM_CTLCOLOR消息的结果发送MFC应用程序中关闭模式对话框的顺序1.OnClose()消息响应函数,响应WM_CLOSE消息,当"关闭"按钮被单击的时候,该函数被调用2.OnKillFocus()消息响应函数,响应WM_KILLFOCUS消息,当一个窗口即将失去键盘输入焦点以前被发送3.OnDestroy()消息响应函数,响应WM_DESTROY消息,当一个窗口即将被销毁时,被发送4.OnNcDestroy()消息响应函数,响应WM_NCDESTROY消息,当一个窗口被销毁以后被发送5.PostNcDestroy() 重载函数,作为处理OnNcDestroy()函数的最后动作被CWnd调用打开无模式对话框的顺序1.PreSubclassWindow()重载函数,允许用户首先子分类一个窗口2.OnCreate()消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建3.OnSize()消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化4.OnMove()消息响应函数,响应WM_MOVE消息,发送此消息以告诉窗口正在移动5.OnSetFont()消息响应函数,响应WM_SETFONT消息,发送此消息以允许改变对话框中控件的字体。
mfc 主界面函数中线程等待避免界面卡死的处理方法
mfc 主界面函数中线程等待避免界面卡死的处理方法在MFC主界面函数中,如果执行某些耗时的操作,比如网络请求或者大量的数据处理,会导致界面卡死,用户无法进行其他操作。
为了避免这种情况,可以使用线程等待的方法来实现异步操作,保证界面的流畅性。
一种常见的处理方法是使用CWinThread类创建一个新的线程,在该线程中执行耗时操作,然后通过主线程与子线程之间的通信来实现异步操作。
具体的步骤如下:1. 在主界面函数中创建一个新的CWinThread对象,例如:```cppCWinThread* pThread = AfxBeginThread(ThreadFunc, this); ````ThreadFunc`是一个静态成员函数,定义在主界面所属的类中(例如CMainFrame类),用于执行耗时操作。
2. 在`ThreadFunc`函数中执行耗时操作,例如网络请求或者数据处理。
注意,这里需要将`this`指针传递给`ThreadFunc`函数,以便在子线程中可以访问主线程的成员变量和函数。
```cppUINT ThreadFunc(LPVOID pParam){CMainFrame* pMainFrame = (CMainFrame*)pParam;// 执行耗时操作pMainFrame->PostMessage(WM_THREAD_COMPLETE, 0, 0);return 0;}```3. 在主界面的消息映射函数中,处理子线程完成的消息,并更新界面。
```cppBEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)// 其他消息映射ON_MESSAGE(WM_THREAD_COMPLETE, OnThreadComplete)END_MESSAGE_MAP()afx_msg LRESULT OnThreadComplete(WPARAM wParam, LPARAM lParam){// 更新界面return 0;}````WM_THREAD_COMPLETE`是自定义的消息类型,用于通知主线程子线程已经完成。
mfc多线程编程 主线程等待子线程退出函数 -回复
mfc多线程编程主线程等待子线程退出函数-回复MFC多线程编程是指使用Microsoft Foundation Classes (MFC)框架开发多线程应用程序的过程。
在这种编程模型中,主线程是应用程序的入口点,而子线程则用于执行一些独立的任务,从而提高应用程序的性能和响应能力。
在实际开发中,经常需要主线程等待子线程执行完毕的情况。
这样做的目的是确保主线程在继续执行之前,所有的子线程已经完成任务,从而避免可能的数据竞争和资源冲突。
本文将详细介绍如何在MFC多线程编程中,实现主线程等待子线程退出函数的方法,以及一些相关的注意事项。
第一步:创建子线程在MFC中,可以通过调用AfxBeginThread函数来创建子线程。
该函数的原型如下:CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0,LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);其中,pfnThreadProc是子线程函数的指针,LPVOID pParam是传递给子线程函数的参数。
以下是一个示例的子线程函数的定义:UINT MyThreadFunction(LPVOID pParam){子线程的任务代码...return 0;}要创建子线程,可以在主线程中调用AfxBeginThread函数。
例如:CWinThread* pThread = AfxBeginThread(MyThreadFunction, pParam);这将创建一个新的子线程,并启动执行MyThreadFunction函数。
参数pParam是可选的,可根据实际需要进行传递。
第二步:等待子线程退出函数主线程需要等待子线程执行完毕后才能继续执行。
MFC六大核心机制
MFC六大核心机制1.消息映射机制:MFC使用明确的消息映射机制来处理用户界面和系统事件。
应用程序通过重写消息映射函数来处理不同的消息事件,如鼠标点击、按键操作等。
消息映射机制使得开发者可以方便地响应和处理不同的用户交互动作。
2. 文档视图(Doc/View)体系:MFC采用了文档视图体系,将应用程序数据(文档)和用户界面(视图)分离。
文档表示应用程序的数据,视图代表用户界面,通过文档视图模式可以实现多视图的显示和操作。
开发者可以自定义文档类和视图类,通过它们来管理和展示数据。
3.对象序列化机制:对象序列化是指将对象的状态转换为可以存储或传输的格式,以便于在不同的环境中恢复对象的状态。
MFC提供了强大的对象序列化支持,可以方便地对应用程序的数据进行存储和加载。
开发者只需将需要序列化的成员变量标记为可序列化,并实现相关的序列化函数即可实现数据的持久化。
4.多线程支持:MFC提供了多线程支持,使得应用程序可以在多个线程中同时执行任务。
开发者可以使用MFC提供的线程类来创建和管理线程,并通过消息机制进行线程间的通信。
多线程支持有助于提高应用程序的性能和响应能力。
MFC的运行时类是一组用于封装常用功能的类,包括字符串操作、容器类、文件I/O等。
这些类提供了方便、高效的操作接口,减少了开发者对底层操作的依赖。
开发者可以直接使用MFC提供的运行时类来简化开发过程。
6.扩展性:MFC提供了丰富的扩展性机制,包括自定义控件、自定义对话框、自定义视图等。
开发者可以通过派生已有的MFC类来创建自定义的控件或界面,以满足特定的应用程序需求。
扩展性机制使得开发者可以充分发挥自己的创造力和想象力,实现更加个性化的应用程序。
总结:MFC六大核心机制为开发者提供了丰富的类和功能,使得开发Windows图形界面应用程序更加简单和高效。
通过消息映射机制、文档视图体系、对象序列化机制、多线程支持、运行时类和扩展性机制,开发者可以轻松地实现各种应用程序的需求,并提供更好的用户体验。
mfc 线程afxbeginthread基本用法,传多个参数
mfc 线程afxbeginthread基本用法,传多个参数===========MFC(Microsoft Foundation Classes)是微软提供的一个用于开发Windows应用程序的类库,它提供了许多方便的类和函数,用于简化Windows应用程序的开发。
在MFC中,线程是常用的概念之一,用于在程序中实现多任务处理。
`AfxBeginThread`函数是MFC中用于创建新线程的函数,它可以接受多个参数,用于指定线程的参数和回调函数。
一、基本用法------`AfxBeginThread`函数的原型如下:```cppvoid AFXAPI AfxBeginThread(DWORD (CALLBACK* lpfn)(void*),void* lpParam);```其中,`lpfn`是一个指向线程函数的指针,它接受一个`void*`类型的参数,并返回一个`DWORD`类型的结果。
`lpParam`是一个指向线程函数的参数的指针。
下面是一个简单的示例,演示了如何使用`AfxBeginThread`函数创建新线程,并传递多个参数:```cppvoid MyThreadFunction(void* param){// 在这里实现线程函数逻辑// 可以通过传递的参数进行相应的处理// ...}int main(){// 创建新线程,并传递多个参数DWORD threadId;CWinThread* pThread = AfxBeginThread(MyThreadFunction, NULL, 1, "MyThread", &threadId);if (pThread){// 线程创建成功,可以进行相应的操作...}else{// 线程创建失败,可以处理错误情况...}return 0;}```在上面的示例中,我们创建了一个新线程,并传递了四个参数:`MyThreadFunction`是线程函数的指针,`NULL`是线程函数的参数(因为这里没有需要传递的参数),`1`是线程ID,最后一个参数是线程的名称(可选)。
MFC启动和关闭线程
MFC启动和关闭线程1、启动线程:CWinThread* AfxBeginThread( 线程函数,this );2、通常导致线程终⽌的两种情况是:控制函数退出或不允许线程完成运⾏。
如果字处理器使⽤后台打印线程,若成功完成打印,则控制函数将正常终⽌。
但是,如果⽤户要取消打印,后台打印线程则不得不提前终⽌。
本主题介绍如何实现每⼀种情况,以及在终⽌后如何获取线程的退出代码。
(1)正常线程终⽌对于辅助线程,正常线程终⽌很简单:退出控制函数并返回表⽰终⽌原因的值。
可以使⽤函数或 return 语句。
⼀般情况下,0 表⽰成功完成,但这取决于您⾃⼰。
对于⽤户界⾯线程,该过程也很简单:从⽤户界⾯线程内调⽤ Platform SDK 中的。
PostQuitMessage 采⽤的唯⼀参数是线程的退出代码。
对于辅助线程,0 通常表⽰成功完成。
(2)过早的线程终⽌过早终⽌线程⼏乎⼀样简单:从线程内调⽤。
将所需的退出代码作为唯⼀参数传递。
这将停⽌执⾏线程、解除对线程堆栈的分配、分离附加到线程的所有 DLL 并从内存中删除线程对象。
必须从要终⽌的线程内调⽤ AfxEndThread。
如果要从其他线程终⽌线程,必须设置两个线程间的通信⽅法。
举⼀个例⼦:可以创建⼀个信号量,⽤WaitForSingleObject函数来检测该信号量的状态。
成员变量 m_hThreadEvent;m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );线程的执⾏函数:for( ; ;){DWORD dwRetVal;dwRetVal = WaitForSingleObject( m_hThreadEvent, 100 );if ( dwRetVal == WAIT_TIMEOUT ){// TODO:}else{// stop receive text thread.DWORD dwExitCode;GetExitCodeThread( m_pThreadRecv->m_hThread, &dwExitCode );AfxEndThread( dwExitCode, TRUE );}}要结束线程时,使⽤SetEvent,将信号量置为有信号。
MFC消息机制详解
消息映射的实现Windows消息概述Windows应用程序的输入由Windows系统以消息的形式发送给应用程序的窗口。
这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。
消息的分类队列消息和非队列消息从消息的发送途径上看,消息分两种:队列消息和非队列消息。
队列消息送到系统消息队列,然后到线程消息队列;非队列消息直接送给目的窗口过程。
这里,对消息队列阐述如下:Windows维护一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。
鼠标、键盘事件由鼠标或键盘驱动程序转换成输入消息并把消息放进系统消息队列,例如WM_MOUSEMOVE、WM_LBUTTONUP、WM_KEYDOWN、WM_CHAR等等。
Windows 每次从系统消息队列移走一个消息,确定它是送给哪个窗口的和这个窗口是由哪个线程创建的,然后,把它放进窗口创建线程的线程消息队列。
线程消息队列接收送给该线程所创建窗口的消息。
线程从消息队列取出消息,通过Windows把它送给适当的窗口过程来处理。
除了键盘、鼠标消息以外,队列消息还有WM_PAINT、WM_TIMER和WM_QUIT。
这些队列消息以外的绝大多数消息是非队列消息。
系统消息和应用程序消息从消息的来源来看,可以分为:系统定义的消息和应用程序定义的消息。
系统消息ID的范围是从0到WM_USER-1,或0X80000到0XBFFFF;应用程序消息从WM_USER(0X0400)到0X7FFF,或0XC000到0XFFFF;WM_USER到0X7FFF范围的消息由应用程序自己使用;0XC000到0XFFFF范围的消息用来和其他应用程序通信,为了ID的唯一性,使用::RegisterWindowMessage来得到该范围的消息ID。
消息结构和消息处理消息的结构为了从消息队列获取消息信息,需要使用MSG结构。
MFC中进度条控件的使用方法
MFC中进度条控件的使用方法MFC(Microsoft Foundation Class)进度条控件是一种用于显示任务进度的常见控件,可以在界面中显示一个动态的进度条,以便用户了解任务的进度情况。
在本文中,将介绍MFC中如何使用进度条控件,并详细说明其使用方法。
1.创建进度条控件在MFC应用程序的对话框资源中添加一个进度条控件,控件ID可以自定义。
然后在对应的对话框类中添加一个变量用于关联该控件,方法如下:```cpp#include <afxcmn.h> // 导入控件类的头文件class CMyDialog : public CDialogEx//...protected:CProgressCtrl m_progress; // 声明一个变量用于关联进度条控件};```2.初始化进度条在对话框类中的OnInitDialog(函数中,通过m_progress变量获取进度条控件的指针,并进行初始化设置。
```cppBOOL CMyDialog::OnInitDialogCDialogEx::OnInitDialog(;//获取进度条控件的指针CProgressCtrl* pProgress =(CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);//设置进度条范围(默认为0-100)pProgress->SetRange(0, 100);//设置进度条初始位置pProgress->SetPos(0);return TRUE;}```3.更新进度条的进度在任务进行中,可以通过SetPos(函数设置进度条的当前位置,用以更新进度条的进度。
```cppvoid CMyDialog::DoTaskfor (int i = 0; i <= 100; i++)m_progress.SetPos(i);//执行任务代码...}}```4.设置进度条样式进度条控件还支持一些样式设置,可以通过SetStyle(函数进行设置。
用MFC实现多线程
用MFC实现多线程MFC(Microsoft Foundation Class)是微软公司提供的C++ 类库,用于开发 Windows 平台上的桌面应用程序。
MFC 提供了许多实用工具,用于简化 Windows 编程任务,包括多线程编程。
在本文中,我们将介绍如何使用 MFC 实现多线程。
多线程编程是指在一个程序中同时执行多个线程,每个线程都有自己的执行流程。
多线程编程可以提高程序的性能和响应速度,特别是在处理大量计算或耗时的任务时。
要在 MFC 中实现多线程,我们可以使用 CWinThread 类来创建和管理线程。
下面是一个简单的示例,演示了如何使用 MFC 创建一个多线程应用程序。
首先,我们需要在MFC应用程序的主类中添加一个成员函数,该函数将被作为线程函数调用。
在这个示例中,我们将创建一个计算从1到100的和的线程。
```cppUINT CalculationThread(LPVOID pParam)int sum = 0;for (int i = 1; i <= 100; i++)sum += i;}CString strResult;strResult.Format(_T("Sum is %d"), sum);AfxMessageBox(strResult);return 0;}```接下来,在应用程序的`InitInstance`函数中创建线程对象并启动线程。
```cppBOOL CMyApp::InitInstance//...//创建线程对象CWinThread* pThread = AfxBeginThread(CalculationThread, NULL);//...return TRUE;```通过调用`AfxBeginThread`函数,我们将线程函数`CalculationThread`和参数指针`NULL`传递给 MFC,以创建一个新的线程。
MFC线程间通信方法和相关类,api函数的详细介绍和例子
2、线程的管理和操作
(一)线程的启动
创建一个用户界面线程,首先要从类CwinThread产生一个派生类,同时必须使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现这个CwinThread派生类。第二步是根据需要重载该派生类的一些成员函数如:ExitInstance()、InitInstance()、OnIdle()、PreTranslateMessage()等函数。最后调用AfxBeginThread()函数的一个版本:CWinThread*
//The Thread Function;
UINT ThreadFunction(LPVOID pParam)//线程函数
{
while(!bend)
{
Beep(100,100);
Sleep(1000);
}
return 0;
}
/////////////////////////////////////////////////////////////
线程被分为两种:用户界面线程和工作线程(又称为后台线程)。用户界面线程通常用来处理用户的输入并响应各种事件和消息,其实,应用程序的主执行线程CWinAPP对象就是一个用户界面线程,当应用程序启动时自动创建和启动,同样它的终止也意味着该程序的结束,进程终止。工作线程用来执行程序的后台处理任务,比如计算、调度、对串口的读写操作等,它和用户界面线程的区别是它不用从CWinThread类派生来创建,对它来说最重要的是如何实现工作线程任务的运行控制函数。工作线程和用户界面线程启动时要调用同一个函数的不同版本;最后需要读者明白的是,一个进程中的所有线程共享它们父进程的变量,但同时每个线程可以拥有自己的变量。
MFC六大核心机制
MFC六大核心机制MFC(Microsoft Foundation Classes)是微软公司开发的一套基于C++语言的应用程序框架。
它提供了一系列类和函数库,方便开发人员构建Windows应用程序。
MFC框架包含了许多核心机制,下面将介绍其中的六大核心机制。
一、消息映射机制:消息映射机制是MFC框架的核心之一,它用于处理Windows消息。
Windows操作系统是事件驱动的,应用程序需要响应来自用户的输入或系统的消息。
通过消息映射机制,开发人员可以向MFC框架注册处理特定消息的函数,当该消息发生时,框架将自动调用相应的函数进行处理。
开发人员只需要在类的消息映射表中添加相应的消息与处理函数的映射关系,就可以实现消息的处理。
二、文档/视图机制:文档/视图机制是MFC框架中用来管理应用程序数据和图形界面显示的一种机制。
应用程序的数据和用户界面是相互独立的,通过文档/视图机制可以将二者进行分离。
开发人员可以创建一个或多个文档类来管理数据,同时可以创建一个或多个视图类来负责显示用户界面。
MFC框架会自动处理数据和界面之间的同步,例如当数据发生变化时,会自动更新界面;当用户修改界面时,会自动更新数据。
三、消息响应机制:消息响应机制是MFC框架中用来处理用户输入和系统消息的一种机制。
开发人员可以通过消息响应机制,将特定的消息与相应的处理函数进行关联,当该消息发生时,框架会自动调用相应的处理函数。
例如,开发人员可以通过响应鼠标点击消息来实现用户点击按钮的响应,或者通过响应键盘输入消息来实现用户输入的响应。
四、对象模型机制:对象模型机制是MFC框架中用来管理对象的一种机制。
MFC框架使用了一种轻量级的对象模型,对象之间的关系通过继承和组合来实现。
开发人员可以创建自己的类并继承自MFC提供的基类,以实现各种功能。
MFC框架提供了丰富的基类库,包括窗口类、对话框类、控件类等,开发人员可以通过继承这些基类来快速构建自己的应用程序。
mfc项目执行流程
mfc项目执行流程MFC(Microsoft Foundation Class)是一个C++库,用于创建Windows桌面应用程序。
MFC项目的执行流程通常遵循以下一般步骤:1. 创建MFC应用程序项目:使用Visual Studio或其他适用的开发环境创建一个MFC应用程序项目。
在创建项目时,您可以选择项目类型(如单文档、多文档、对话框等)和其他项目属性。
2. 初始化应用程序:MFC应用程序的入口点通常是_tWinMain 函数。
在此函数中,您可以执行应用程序级别的初始化工作,例如创建主窗口对象、初始化MFC框架等。
3. 创建主窗口:通常,MFC应用程序会创建一个主窗口,这是应用程序的主要用户界面。
主窗口通常是派生自CFrameWnd或CDialog的窗口类,具有菜单、工具栏、状态栏等。
4. 消息循环:MFC应用程序通过消息循环来处理用户输入和操作系统事件。
消息循环是一个无限循环,等待用户输入、消息和事件,然后分派它们到相应的窗口和控件。
5. 响应事件和消息:在主窗口、对话框和其他控件中,您可以处理并响应用户操作和事件,例如按钮点击、菜单项选择、窗口关闭等。
这通常涉及到处理MFC消息处理函数,如OnCommand、OnPaint 等。
6. 窗口绘图:如果应用程序需要绘制图形、文本或其他内容,您可以重写OnPaint消息处理函数,然后在其中进行绘图操作。
7. 资源管理:MFC应用程序通常使用资源文件(如对话框资源、位图、图标等)来定义界面元素和图形资源。
您可以使用Visual Studio的资源编辑器管理这些资源。
8. 保存和加载数据:如果应用程序需要保存和加载数据,您可以实现相关的数据持久性功能,如将数据保存到文件、数据库或其他存储介质。
9. 编译和构建:完成代码编写后,您需要编译和构建MFC应用程序,以生成可执行文件(.exe)。
10. 测试和调试:对应用程序进行测试和调试,确保其正常运行,以处理潜在的错误和异常情况。
MFC多线程控制进度条
界面如下:(1)加入三个CprogressCtrl空间,分别设置这三个空间的变量CProgressCtrl m_hThread3;CProgressCtrl m_hThread2;CProgressCtrl m_hThread1;(2)声明三个线程函数(在dlg类的public部分就好)static DWORD __stdcall ThreadOne( LPVOID lpParameter);static DWORD __stdcall ThreadTwo( LPVOID lpParameter);static DWORD __stdcall ThreadThree( LPVOID lpParameter);以及三个线程句柄用来接收创建线程的返回值HANDLE m_hThreadOne;HANDLE m_hThreadTwo;HANDLE m_hThreadThree;static的作用是,因为定义的线程函数在类里,如果不是静态函数,调用时需要定义一个对象,有对象调用该函数,而我这里定义为静态函数使得这个函数不属于任何对象,可以直接调用,如果线程函数定义为一个全局变量,也就是在类的外面定义,则不需要这样。
__stdcall标识函数的参数由右向左压入堆栈。
(3)为进度条设置范围在OnInitDialog()中m_hThread1.SetRange(0,100000);m_hThread2.SetRange(0,100000);m_hThread3.SetRange(0,100000);(4)创建线程函数void CThreadDlg::OnCreatethread(){m_hThreadOne=CreateThread(NULL,100,ThreadOne,(void*)this,CREATE_SUSPENDED,NULL); // CREATE_SUSPENDED标识创建的线程可以被挂起的SetThreadPriority(m_hThreadOne,THREAD_PRIORITY_ABOVE_NORMAL);//标识创建的线程具有的优先级别m_hThreadTwo=CreateThread(NULL,100,ThreadTwo,(void*)this,CREATE_SU SPENDED,NULL);SetThreadPriority(m_hThreadTwo,THREAD_PRIORITY_NORMAL);m_hThreadThree=CreateThread(NULL,100,ThreadThree,(void*)this,CREATE_S USPENDED,NULL);SetThreadPriority(m_hThreadThree,THREAD_PRIORITY_BELOW_NORMAL);}(5)启动线程void CThreadDlg::OnThreadrun(){// TODO: Add your control notification handler code hereResumeThread(m_hThreadOne);ResumeThread(m_hThreadTwo);ResumeThread(m_hThreadThree);}(6)挂载线程void CThreadDlg::OnThreadup(){SuspendThread(m_hThreadOne);SuspendThread(m_hThreadTwo);SuspendThread(m_hThreadThree);}(7)恢复线程void CThreadDlg::OnThreadrev(){ResumeThread(m_hThreadOne);ResumeThread(m_hThreadTwo);ResumeThread(m_hThreadThree);}(8)具体的三个线程的功能函数DWORD CThreadDlg::ThreadTwo( LPVOID lpParam) // thread data){CThreadDlg* pDlg = (CThreadDlg*)lpParam;int low,high,pos;pos = pDlg->m_hThread2.GetPos();pDlg->m_hThread2.GetRange(low,high);while (pos<high){pos = pDlg->m_hThread2.GetPos();pDlg->m_hThread2.SetPos(pos+1);}pDlg->m_hThread2.SetPos(0);return 0;}。
MFC多线程和延时
MFC多线程2009年08月01日星期六16:52一、问题的提出编写一个耗时的单线程程序:新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下:void CSingleThreadDlg::OnSleepSixSecond(){Sleep(6000); //延时6秒}编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。
为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。
二、多线程概述进程和线程都是操作系统的概念。
进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。
线程是进程内部的一个执行单元。
系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。
主执行线程终止了,进程也就随之终止。
每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。
用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。
一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。
多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。
要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU 时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。
由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。
MFC生命周期
1、MFC程序的启动过程MFC的封装机制隐藏了函数的执行过程,这使MFC程序不如传统的Win32程序具有清晰的运行流程。
但是作为Windows程序,MFC程序也有WinMain。
下面的启动过程分析基于单文档应用程序SinDocEx:2、MFC程序的挂起状态Run——程序挂起Run函数通过消息循环,检查消息队列中是否有需要处理的消息。
如果有消息需要处理,则Run就调度它;如果没有任何消息需要处理,则Run调用OnIdle,以便执行用户或框架需要完成的空闲时间处理。
如果没有任何消息,也没有任何可执行的空闲处理,则应用程序一直等待消息产生,应用也就被挂起。
空闲处理MFC程序的空闲处理,及Run中的OnIdle。
MFC实现了这样一个Idle处理机制:在没有消息可以处理时,进行Idle处理。
3、MFC程序的终止一个MFC应用程序的生命周期(一)程序的进入点MFC作为Win32 API的一种封装,它的程序进入点自然是WinMain。
但是,这个WinMain也被封装起来,用户是看不到的,只是在编译器进行连接时会被自动连接。
下面我们就来寻找一下MFC程序被隐藏了的WinMain。
搜索MFC的源文件,可以发现MFC的WinMain定义在 appmodul.cpp中。
此文件可以在VC的MFC src文件夹中找到extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstanc e, __in LPTSTR lpCmdLine, int nCmdShow) { // call share d/exported WinMain return AfxWinMain(hInstance, hPrevInstance, lpCmdLi ne, nCmdShow); }这里的名字虽然是_tWinMain但是我们使用“转到定义”菜单项跳转,会发现实际上这是一个宏:#define _tWinMain wWinMain作为测试我们在VS中新建一个SDI MFC工程,起名为Test,VC会自动生成五个类CAboutDlgCMainFrameCTestAppCTestDocCTestView在appmodul.cpp中的WinMain中加入一个断点,然后运行程序。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
8.MFC的进程和线程1.Win32的进程和线程概念进程是一个可执行的程序,由私有虚拟地址空间、代码、数据和其他操作系统资源(如进程创建的文件、管道、同步对象等)组成。
一个应用程序可以有一个或多个进程,一个进程可以有一个或多个线程,其中一个是主线程。
线程是操作系统分时调度分配CPU时间的基本实体。
一个线程可以执行程序的任意部分的代码,即使这部分代码被另一个线程并发地执行;一个进程的所有线程共享它的虚拟地址空间、全局变量和操作系统资源。
之所以有线程这个概念,是因为以线程而不是进程为调度对象效率更高:∙由于创建新进程必须加载代码,而线程要执行的代码已经被映射到进程的地址空间,所以创建、执行线程的速度比进程更快。
∙一个进程的所有线程共享进程的地址空间和全局变量,所以简化了线程之间的通讯。
1.Win32的进程处理简介因为MFC没有提供类处理进程,所以直接使用了Win32 API函数。
1.进程的创建调用CreateProcess函数创建新的进程,运行指定的程序。
CreateProcess的原型如下:BOOL CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCTSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);其中:lpApplicationName指向包含了要运行模块名字的字符串。
lpCommandLine指向命令行字符串。
lpProcessAttributes描述进程的安全性属性,NT下有用。
lpThreadAttributes描述进程初始线程(主线程)的安全性属性,NT下有用。
bInHeritHandles表示子进程(被创建的进程)是否可以继承父进程的句柄。
可以继承的句柄有线程句柄、有名或无名管道、互斥对象、事件、信号量、映像文件、普通文件和通讯端口等;还有一些句柄不能被继承,如内存句柄、DLL实例句柄、GDI句柄、URER句柄等等。
子进程继承的句柄由父进程通过命令行方式或者进程间通讯(IPC)方式由父进程传递给它。
dwCreationFlags表示创建进程的优先级类别和进程的类型。
创建进程的类型分控制台进程、调试进程等;优先级类别用来控制进程的优先级别,分Idle、Normal、High、Real_time四个类别。
lpEnviroment指向环境变量块,环境变量可以被子进程继承。
lpCurrentDirectory指向表示当前目录的字符串,当前目录可以继承。
lpStartupInfo指向StartupInfo结构,控制进程的主窗口的出现方式。
lpProcessInformation指向PROCESS_INFORMATION结构,用来存储返回的进程信息。
从其参数可以看出创建一个新的进程需要指定什么信息。
从上面的解释可以看出,一个进程包含了很多信息。
若进程创建成功的话,返回一个进程信息结构类型的指针。
进程信息结构如下:typedef struct _PROCESS_INFORMATION {HANDLE hProcess;HANDLE hThread;DWORD dwProcessId;DWORD dwThreadId;}PROCESS_INFORMATION;进程信息结构包括进程句柄,主线程句柄,进程ID,主线程ID。
2.进程的终止进程在以下情况下终止:∙调用ExitProcess结束进程;∙进程的主线程返回,隐含地调用ExitProcess导致进程结束;∙进程的最后一个线程终止;∙调用TerminateProcess终止进程。
∙当要结束一个GDI进程时,发送WM_QUIT消息给主窗口,当然也可以从它的任一线程调用ExitProcess。
1.Win32的线程1.线程的创建使用CreateThread函数创建线程,CreateThread的原型如下:HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags, // creation flagsLPDWORD lpThreadId);其中:lpThreadAttributes表示创建线程的安全属性,NT下有用。
dwStackSize指定线程栈的尺寸,如果为0则与进程主线程栈相同。
lpStartAddress指定线程开始运行的地址。
lpParameter表示传递给线程的32位的参数。
dwCreateFlages表示是否创建后挂起线程(取值CREATE_SUSPEND),挂起后调用ResumeThread继续执行。
lpThreadId用来存放返回的线程ID。
∙线程的优先级别进程的每个优先级类包含了五个线程的优先级水平。
在进程的优先级类确定之后,可以改变线程的优先级水平。
用SetPriorityClass设置进程优先级类,用SetThreadPriority设置线程优先级水平。
Normal级的线程可以被除了Idle级以外的任意线程抢占。
1.线程的终止以下情况终止一个线程:∙调用了ExitThread函数;∙线程函数返回:主线程返回导致ExitProcess被调用,其他线程返回导致ExitThread被调用;∙调用ExitProcess导致进程的所有线程终止;∙调用TerminateThread终止一个线程;∙调用TerminateProcess终止一个进程时,导致其所有线程的终止。
当用TerminateProcess或者TerminateThread终止进程或线程时,DLL的入口函数DllMain不会被执行(如果有DLL的话)。
1.线程局部存储如果希望每个线程都可以有线程局部(Thread local)的静态存储数据,可以使用TLS线程局部存储技术。
TLS为进程分配一个TLS索引,进程的每个线程通过这个索引存取自己的数据变量的拷贝。
TLS对DLL是非常有用的。
当一个新的进程使用DLL时,在DLL入口函数DllMain 中使用TlsAlloc分配TLS索引,TLS索引就作为进程私有的全局变量被保存;以后,当该进程的新的线程使用DLL时(Attahced to DLL),DllMain给它分配动态内存并且使用TlsSetValue把线程私有的数据按索引保存。
DLL函数可以使用TlsGetValue按索引读取调用线程的私有数据。
TLS函数如下:∙DWORD TlsAlloc()在进程或DLL初始化时调用,并且把返回值(索引值)作为全局变量保存。
∙BOOL TlsSetValue(DWORD dwTlsIndex, //TLS index to set value forLPVOID lpTlsValue //value to be stored);其中:dwTlsIndex是TlsAlloc分配的索引。
lpTlsValue是线程在TLS槽中存放的数据指针,指针指向线程要保存的数据。
线程首先分配动态内存并保存数据到此内存中,然后调用TlsSetValue保存内存指针到TLS槽。
∙LPVOID TlsGetValue(DWORD dwTlsIndex // TLS index to retrieve value for);其中:dwTlsIndex是TlsAlloc分配的索引。
当要存取保存的数据时,使用索引得到数据指针。
∙BOOL TlsFree(DWORD dwTlsIndex // TLS index to free);其中:dwTlsIndex是TlsAlloc分配的索引。
当每一个线程都不再使用局部存储数据时,线程释放它分配的动态内存。
在TLS 索引不再需要时,使用TlsFree释放索引。
1.线程同步同步可以保证在一个时间内只有一个线程对某个资源(如操作系统资源等共享资源)有控制权。
共享资源包括全局变量、公共数据成员或者句柄等。
同步还可以使得有关联交互作用的代码按一定的顺序执行。
Win32提供了一组对象用来实现多线程的同步。
这些对象有两种状态:获得信号(Signaled)或者没有或则信号(Notsignaled)。
线程通过Win32 API提供的同步等待函数(Waitfunctions)来使用同步对象。
一个同步对象在同步等待函数调用时被指定,调用同步函数地线程被阻塞(blocked),直到同步对象获得信号。
被阻塞的线程不占用CPU时间。
1.同步对象同步对象有:Critical_section(关键段),Event(事件),Mutex(互斥对象),Semaphores(信号量)。
下面,解释怎么使用这些同步对象。
1.关键段对象:首先,定义一个关键段对象cs:CRITICAL_SECTION cs;然后,初始化该对象。
初始化时把对象设置为NOT_SINGALED,表示允许线程使用资源:InitializeCriticalSection(&cs);如果一段程序代码需要对某个资源进行同步保护,则这是一段关键段代码。
在进入该关键段代码前调用EnterCriticalSection函数,这样,其他线程都不能执行该段代码,若它们试图执行就会被阻塞。
完成关键段的执行之后,调用LeaveCriticalSection函数,其他的线程就可以继续执行该段代码。
如果该函数不被调用,则其他线程将无限期的等待。
2.事件对象首先,调用CreateEvent函数创建一个事件对象,该函数返回一个事件句柄。
然后,可以设置(SetEvent)或者复位(ResetEvent)一个事件对象,也可以发一个事件脉冲(PlusEvent),即设置一个事件对象,然后复位它。
复位有两种形式:自动复位和人工复位。
在创建事件对象时指定复位形式。
自动复位:当对象获得信号后,就释放下一个可用线程(优先级别最高的线程;如果优先级别相同,则等待队列中的第一个线程被释放)。
人工复位:当对象获得信号后,就释放所有可利用线程。
最后,使用CloseHandle销毁创建的事件对象。
3.互斥对象首先,调用CreateMutex创建互斥对象;然后,调用等待函数,可以的话利用关键资源;最后,调用RealseMutex释放互斥对象。