C++ 多线程编码 基础教程一

原文分四篇,地址为:

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

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值