当前位置 博文首页 > 启舰:C++ 多线程编码 基础教程一

    启舰:C++ 多线程编码 基础教程一

    作者:[db:作者] 时间:2021-06-12 21:45

    原文分四篇,地址为:

    C++多线程(一):http://blog.csdn.net/richerg85/article/details/7438314

    C++多线程(二):http://blog.csdn.net/richerg85/article/details/7447470

    C++多线程(三):http://blog.csdn.net/richerg85/article/details/7450818

    C++多线程(四):http://blog.csdn.net/richerg85/article/details/7451729

    c++多线程(一)?

    多线程的简介

    线程---操作系统调度的最小单位。线程包含在进程中,是进程中实际运行的单位。一个进程中可以同时运行多个线程,每个线程可以执行不同的任务,这就是所谓的多线程。同一进程中的多个线程将共享该进程中的全部系统资源,如虚拟地址空间、文件描述符和信号处理等,但是同一个进程中的多个线程都有各自的调用栈、寄存器环境和线程本地存储。

    ?????? 对于单核(单CPU)系统来说,即便处理器一次只能运行一个线程,但是操作系统通过时间片轮转技术,在不同的线程之间进行切换,让用户产生可以同时处理多个任务的错觉,这样的程序运行机制称为软件的多线程。

    ?????? 对于多核(多个CPU)系统来说,这样的系统能同时进行真正的多线程多任务处理。这种运行机制可以称为硬件的多线程技术。

    ?????? 多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:
      1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
      2) 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
      3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

    多线程编程实例1

    ?????? 说明:本系列所有的实例都是在vc6.0下实现的,并且都是基于MFC AppWizard[exe]工程创建的“Dialog based”应用程序。

    ?????? 实例1,简单的多线程,实现动态显示时间

    工程名称为Mthread1,首先在Mthread1Dlg.h中声明线程函数---void ThreadProc(),此函数为全局函数。

    ?????? 部分代码如下:

    // Mthread1Dlg.h : header file
    //
       ... ...
    
    void ThreadProc();//线程函数声明
    class CMthread1Dlg : public CDialog
    {
         ... ...
    protected:
    	HICON m_hIcon;
    	HANDLE hThread;//线程句柄
    	... ...
    
    	DECLARE_MESSAGE_MAP()
    };

    MthreadDlg.cpp

    // Mthread1Dlg.cpp : implementation file
    //
    
    /
    // CAboutDlg dialog used for App About
    volatile BOOL m_bRun;//代表线程是否正常运行
    
    void ThreadProc() //线程函数
    {
    	CTime time;
    	CString strTime;
    	m_bRun = TRUE;
    
    	while(m_bRun)
    	{
    		time = CTime::GetCurrentTime();
    		strTime = time.Format("%H:%M:%S");
    
    		::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);
    		Sleep(1000);
    	}
    }
    class CAboutDlg : public CDialog
    {
       ...  ...
    void CMthread1Dlg::OnStart()   
    {
    	// TODO: Add your control notification handler code here
    	hThread = CreateThread(
    				 NULL,									 // SD
    				 0,									 // initial stack size
    				(LPTHREAD_START_ROUTINE)ThreadProc,    // thread function
    				NULL,									 // thread argument
    				0,									 // creation option
    				 &threadID								 // thread identifier
    				);
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
    }	
    
    void CMthread1Dlg::OnStop() 
    {
    	// TODO: Add your control notification handler code here
    	m_bRun = FALSE;
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    	GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
    }

    执行结果:



    相应函数API说明

    CreateThread

    函数原型:

    HANDLE CreateThread(
     LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
     DWORD dwStackSize,                       // initial stack size
     LPTHREAD_START_ROUTINE lpStartAddress,   // thread function
     LPVOID lpParameter,                      // thread argument
     DWORD dwCreationFlags,                   // creation option
     LPDWORD lpThreadId                       // thread identifier
    );

    此函数在其调用进程的进程空间里创建一个线程。

    参数说明:

    lpThreadAttributes:指向SECURITY_ATTRIBUTES结构体,该结构体决定了函数返回句柄是否被子进线程继承。

    如果为NULL,则不能被继承。

    dwStackSize:指定了线程的堆栈大小,一般为0,使用默认的堆栈大小。

    lpStartAddress:指向应用定义的线程函数,线程函数类型为LPTHREAD_START_ROUTINE。此值代表线程的开始地址。

    lpParameter:线程函数所带的参数。是一个指向结构的指针,不需传递参数时,为NULL。

    dwCreateFlags:线程标志。如果指定为CREATE_SUSPENDED,线程创建的时候的状态为挂起状态,

    线程不会立即执行直到调用ResumeThread函数。

    如果值为0,线程会立即执行。

    lpThreadId:保存新线程的id.

    代码下载地址:

    http://download.csdn.net/detail/richerg85/4209126

    c++多线程(二)

    多线程实例二

    此实例演示采用CreateThread函数在主线程中创建一个线程,并且向创建的线程中传递一个参数。

    由于采用MFC编程,自动生成的代码比较多,还是列出部分实现多线程的代码。

    线程函数:

    void ThreadProc(int count)
    {
    	for (int i=0; i < count; i++)
    	{
    		Beep(2000,50);
    		Sleep(200);
    	}
    }
    主线程函数:

    void CMthread2Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    	UpdateData(TRUE);//从控件中检索数据
    	int count = m_count;
    	hThread = CreateThread(NULL,
    						   0,
    						   (LPTHREAD_START_ROUTINE)ThreadProc,
    						   (VOID *)count,
    						   0,
    						   &threadID
    						   );
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE); //当线程挂起时,为有信号状态
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    }

    注:变量m_count和控件IDC_COUNT做了关联。
    函数说明:

    ? ? ?BOOL UpdateData( BOOL?bSaveAndValidate?= TRUE );

    ? ? MFC中的窗口函数,在对话框中,当建立控件和变量之间的关联关系后,修改变量值,希望对话框更新显示,则bSaveAndValidate=FALSE,即调用UpdateData(FALSE);当需要获取对话框中控件输入的值时,则bSaveAndValidate=TRUE,即调用UpdateData(TRUE)。

    ? ??

    ? ?DWORD WaitForSingleObject(
    ? HANDLE hHandle, ? ? ? ?// handle to object
    ? DWORD dwMilliseconds ? // time-out interval
    );

    ? ? ?此函数的详细描述参见:http://blog.csdn.net/richerg85/article/details/7354154

    注意:

    主线程中,调用了WaitForSingleObject函数,此函数的作用是监视hHandle的状态,当监视的句柄为有信号状态时,即此对象为空闲状态时,此函数返回,才能执行其后的代码。

    在此处,用WaitForSingleObject作用:

    由于c++主程序终止,同时它创建的相应的线程也会终止,它不管子线程是否执行完成,因此,上文中如果不调用WaitForSingleObject函数,则子线程ThreadProc可能没有执行完或者没执行。

    ??

    此程序执行结果图:


    多线程实例三

    此实例演示多线程中,主线程向子线程传递一个结构体。

    在头文件中,声明线程函数及结构体:

    UINT ThreadProc(LPVOID lpParam);
    struct threadInfo
    {
    	UINT nMilliSecond;
    	CProgressCtrl *pctrProcess;
    };
    
    子线程定义函数

    threadInfo myInfo;
    UINT ThreadProc(LPVOID lpParam)
    {
    	threadInfo *pInfo = (threadInfo *)lpParam;
    	for (int i=0; i<100; i++)
    	{
    		int iTmp = pInfo->nMilliSecond;
    		pInfo->pctrProcess->SetPos(i);
    		Sleep(iTmp);
    	}
    	return 0;
    }
    主线程调用子线程函数:

    void CMthread3Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    	UpdateData();//默认为TRUE
    	myInfo.nMilliSecond = m_nMillSecond;
    	myInfo.pctrProcess = &m_ctrProcess;
    
    	hThread = CreateThread(NULL,
    							0,
    							(LPTHREAD_START_ROUTINE)ThreadProc,
    							&myInfo,
    							0,
    							&threadID
    							);
    	/*GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE);
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);*/
    }

    注意注释的部分,如果调用WaitForSingleObject函数,此程序会出现死锁。因为对话框中有个进度条,子线程中设置进度条的进度,但是进度条的刷新需要主线程来完成,当主线程调用WaitForSingleObject函数挂起后,子线程设置正在设置进度条,一直等待主线程将刷新消息出来完毕返回才检测通知事件。这样两个线程一直处于相互等待,出现死锁。

    程序执行结果:


    程序完整源代码下载地址:

    http://download.csdn.net/detail/richerg85/4215491

    下一篇:没有了