C++ 多线程编程总结

一.什么是多线程?

在计算机编程中,一个基本的概念就是同时对多个任务加以控制。许多程序设计问题都要求程序能够停下手头的工作,改为处理其他一些问题,再返回主进程。可以通过多种途径达到这个目的。最开始的时候,那些掌握机器低级语言的程序员编写一些“中断服务例程”,主进程的暂停是通过硬件级的中断实现的。尽管这是一种有用的方法,但编出的程序很难移植,由此造成了另一类的代价高昂问题。中断对那些实时性很强的任务来说是很有必要的。但对于其他许多问题,只要求将问题划分进入独立运行的程序片断中,使整个程序能更迅速地响应用户的请求。

最开始,线程只是用于分配单个处理器的处理时间的一种工具。但假如操作系统本身支持多个处理器,那么每个线程都可分配给一个不同的处理器,真正进入“并行运算”状态。从程序设计语言的角度看,多线程操作最有价值的特性之一就是程序员不必关心到底使用了多少个处理器。程序在逻辑意义上被分割为数个线程;假如机器本身安装了多个处理器,那么程序会运行得更快,毋需作出任何特殊的调校。根据前面的论述,大家可能感觉线程处理非常简单。但必须注意一个问题:共享资源!如果有多个线程同时运行,而且它们试图访问相同的资源,就会遇到一个问题。举个例子来说,两个线程不能将信息同时发送给一台打印机。为解决这个问题,对那些可共享的资源来说(比如打印机),它们在使用期间必须进入锁定状态。所以一个线程可将资源锁定,在完成了它的任务后,再解开(释放)这个锁,使其他线程可以接着使用同样的资源。

二.多线程使用目的:

多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。在开发C++程序时,一般在吞吐量、并发、实时性上有较高的要求。设计C++程序时,总结起来可以从 并发 、 异步、 缓存几点提高效率:

三.多线程使用情形总结:

在此先介绍下常用五种使用情形:

第一种使用情形:任务队列

1.以生产者-消费者模型设计任务队列

生产者-消费者模型是人们非常熟悉的模型,比如在某个服务器程序中,当User数据被逻辑模块修改后,就产生一个更新数据库的任务(produce),投递给IO模块任务队列,IO模块从任务队列中取出任务执行sql操作(consume)。

设计通用的任务队列,示例代码如下:

void task_queue_t::produce(const task_t& task_)
 {
 lock_guard_t lock(m_mutex);
 if (m_tasklist->empty())
{//! 条件满足唤醒等待线程
m_cond.signal();
}
m_tasklist->push_back(task_);
}
 int task_queue_t::comsume(task_t& task_){
 lock_guard_t lock(m_mutex);
 while (m_tasklist->empty())//! 当没有作业时,就等待直到条件满足被唤醒
{
if (false == m_flag)
{
 return -1;
 }
 m_cond.wait();
}
task_ = m_tasklist->front();
m_tasklist->pop_front();
return 0;
 }

2.任务队列使用技巧

2.1 IO与逻辑分离

比如网络游戏服务器程序中,网络模块收到消息包,投递给逻辑层后立即返回,继续接受下一个消息包。逻辑线程在一个没有io操作的环境下运行,以保障实时性。示例:

void handle_xx_msg(long uid, const xx_msg_t& msg){

 logic_task_queue->post(boost::bind(&servie_t::proces, uid, msg));

 }

注意,此模式下为单任务队列,每个任务队列单线程。

2.2连接池与异步回调

比如逻辑Service模块需要数据库模块异步载入用户数据,并做后续处理计算。而数据库模块拥有一个固定连接数的连接池,当执行SQL的任务到来时,选择一个空闲的连接,执行SQL,并把SQL通过回调函数传递给逻辑层。其步骤如下:

(1).预先分配好线程池,每个线程创建一个连接到数据库的连接

(2).为数据库模块创建一个任务队列,所有线程都是这个任务队列的消费者

(3).逻辑层想数据库模块投递sql执行任务,同时传递一个回调函数来接受sql执行结果

示例如下:

void db_t:load(long uid_,boost::functionpost(boost::bind(&db_t:load, uid, func));

注意,此模式下为单任务队列,每个任务队列多线程。

第二种使用情形:日志

本文主要讲C++多线程编程,日志系统不是为了提高程序效率,但是在程序调试、运行期排错上,日志是无可替代的工具,相信开发后台程序的朋友都会使用日志。常见的日志使用方式有如下几种:

(1).流式,如logstream<<“start servie time[%d]” << time(0) <<” app name[%s]” <<app_string.c_str() << endl;

(2).Printf格式如:logtrace(LOG_MODULE,“start servie time[%d] app name[%s]”, time(0),app_string.c_str());

二者各有优缺点,流式是线程安全的,printf格式格式化字符串会更直接,但缺点是线程不安全,如果把app_string.c_str()换成app_string(std::string),编译被通过,但是运行期会crash(如果运气好每次都crash,运气不好偶尔会crash)。我个人钟爱printf风格,可以做如下改进:

(3).增加线程安全,利用C++模板的traits机制,可以实现线程安全。示例:

template

 void logtrace(const char* module, const char* fmt, ARG1 arg1){

 boost::format s(fmt);

 f % arg1;

 }

这样,除了标准类型+std::string传入其他类型将编译不能通过。这里只列举了一个参数的例子,可以重载该版本支持更多参数,如果你愿意,可以支持9个参数或更多。

(4).为日志增加颜色,在printf中加入控制字符,可以再屏幕终端上显示颜色,Linux下示例:printf(“33[32;49;1m [DONE] 33[39;49;0m”)

(5).每个线程启动时,都应该用日志打印该线程负责什么功能。这样,程序跑起来的时候通过top–H– p pid可以得知那个功能使用cpu的多少。实际上,我的每行日志都会打印线程id,此线程id非pthread_id,而其实是线程对应的系统分配的进程id号。

第三种使用情形:性能监控

尽管已经有很多工具可以分析c++程序运行性能,但是其大部分还是运行在程序debug阶段。我们需要一种手段在debug和release阶段都能监控程序,一方面得知程序瓶颈之所在,一方面尽早发现哪些组件在运行期出现了异常。

通常都是使用gettimeofday来计算某个函数开销,可以精确到微妙。可以利用C++的确定性析构,非常方便的实现获取函数开销的小工具,示例如下:

struct profiler{

 profiler(const char* func_name){

 gettimeofday(&tv, NULL);

 }

 ~profiler(){

 struct timeval tv2;

 gettimeofday(&tv2, NULL);

 long cost = (tv.tv_sec - tv.tv_sec) * 1000000 + (tv.tv_usec - tv.tv_usec);

 //! post to some manager

 }
 struct timeval tv;
 };
#define PROFILER() profiler(__FUNCTION__)

Cost应该被投递到性能统计管理器中,该管理器定时讲性能统计数据输出到文件中。

第四种使用情形: Lambda编程

使用foreach代替迭代器

很多编程语言已经内建了foreach,但是c++还没有。所以建议自己在需要遍历容器的地方编写foreach函数。习惯函数式编程的人应该会非常钟情使用foreach,使用foreach的好处多多少少有些,如:

但主要是编程哲学上层面的。

示例:

void user_mgr_t::foreach(boost::function func_){ for (iterator it = m_users.begin(); it != m_users.end() ++it){ func_(it->second); } }

比如要实现dump接口,不需要重写关于迭代器的代码

void user_mgr_t:dump(){

 struct lambda {

 static void print(user_t& user){

 //! print(tostring(user);

 }
 };

 this->foreach(lambda::print);
 }

实际上,上面的代码变通的生成了匿名函数,如果是c++ 11标准的编译器,本可以写的更简洁一些:

this->foreach([](user_t& user) {} );

但是我大部分时间编写的程序都要运行在centos上,你知道吗它的gcc版本是gcc 4.1.2,所以大部分时间我都是用变通的方式使用lambda函数。

Lambda函数结合任务队列实现异步

常见的使用任务队列实现异步的代码如下:

void service_t:async_update_user(long uid){

 task_queue->post(boost::bind(&service_t:sync_update_user_impl,this, uid));

 }

 voidservice_t:sync_update_user_impl(long uid){

 user_t& user = get_user(uid);

 user.update()

 }

这样做的缺点是,一个接口要响应的写两遍函数,如果一个函数的参数变了,那么另一个参数也要跟着改动。并且代码也不是很美观。使用lambda可以让异步看起来更直观,仿佛就是在接口函数中立刻完成一样。示例代码:

void service_t:async_update_user(long uid){

 struct lambda {

 static void update_user_impl(service_t*servie, long uid){

 user_t& user = servie->get_user(uid);

 user.update();

 }

 };

 task_queue->post(boost::bind(&lambda:update_user_impl,this, uid));

 }

这样当要改动该接口时,直接在该接口内修改代码,非常直观。

第五种情形:利用shared_ptr实现map/reduce

Map/reduce的语义是先将任务划分为多个任务,投递到多个worker中并发执行,其产生的结果经reduce汇总后生成最终的结果。Shared_ptr的语义是什么呢?当最后一个shared_ptr析构时,将会调用托管对象的析构函数。语义和map/reduce过程非常相近。我们只需自己实现讲请求划分多个任务即可。示例过程如下:

(1).定义请求托管对象,加入我们需要在10个文件中搜索“ohnice”字符串出现的次数,定义托管结构体如下:

struct reducer{

 voidset_result(int index, long result) {

 m_result[index] = result;

 }

 ~reducer(){

 longtotal = 0;

 for(int i = 0; i < sizeof(m_result); ++i){

 total += m_result[i];

 }

 //!post total to somewhere

 }

 longm_result[10];

 };

1).定义执行任务的 worker

void worker_t:exe(int index_, shared_ptrret) {

 ret->set_result(index, 100);

 }

2).将任务分割后,投递给不同的worker

shared_ptr ret(new reducer());

 for(int i = 0; i < 10; ++i) { task_queue[i]->post(boost::bind(&worker_t:exe,i, ret));

 }

多线程综合使用实例:

CreateThread.h

// MulThreadTest.h : PROJECT_NAME 应用程序的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"		// 主符号

// CMulThreadTestApp:
// 有关此类的实现,请参阅 MulThreadTest.cpp
//

class CMulThreadTestApp : public CWinApp
{
public:
	CMulThreadTestApp();

// 重写
	public:
	virtual BOOL InitInstance();

// 实现

	DECLARE_MESSAGE_MAP()
};

extern CMulThreadTestApp theApp;

MulThreadTest.h

// MulThreadTest.h : PROJECT_NAME 应用程序的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
	#error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"		// 主符号

// CMulThreadTestApp:
// 有关此类的实现,请参阅 MulThreadTest.cpp
//

class CMulThreadTestApp : public CWinApp
{
public:
	CMulThreadTestApp();

// 重写
	public:
	virtual BOOL InitInstance();

// 实现

	DECLARE_MESSAGE_MAP()
};

extern CMulThreadTestApp theApp;

MulThreadTestDlg.h

// MulThreadTestDlg.h : 头文件
//

#pragma once

// CMulThreadTestDlg 对话框
class CMulThreadTestDlg : public CDialog
{
// 构造
public:
	CMulThreadTestDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_MULTHREADTEST_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持

// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedOk();
};

NewWinThread.h

#pragma once

// CNewWinThread

class CNewWinThread : public CWinThread
{
	DECLARE_DYNCREATE(CNewWinThread)

protected:
	CNewWinThread();           // protected constructor used by dynamic creation
	virtual ~CNewWinThread();

public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();

protected:
	DECLARE_MESSAGE_MAP()
};

Resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by MulThreadTest.rc
//
#define IDD_MULTHREADTEST_DIALOG        102
#define IDI_ICON1                       127
#define IDR_MAINFRAME                   128
#define IDD_DIALOG1                     129
#define IDI_ICON2                       131
#define IDI_ICON3                       132
#define IDI_ICON4                       133
#define IDC_PROGRESS1                   1000

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        134
#define _APS_NEXT_COMMAND_VALUE         32771
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

stdafx.h

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件

#pragma once

#ifndef _SECURE_ATL
#define _SECURE_ATL 1
#endif

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN		// 从 Windows 头中排除极少使用的资料
#endif

// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。
// 有关不同平台的相应值的最新信息,请参考 MSDN。
#ifndef WINVER				// 允许使用特定于 Windows XP 或更高版本的功能。
#define WINVER 0x0501		// 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT		// 允许使用特定于 Windows XP 或更高版本的功能。
#define _WIN32_WINNT 0x0501	// 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif						

#ifndef _WIN32_WINDOWS		// 允许使用特定于 Windows 98 或更高版本的功能。
#define _WIN32_WINDOWS 0x0410 // 将它更改为适合 Windows Me 或更高版本的相应值。
#endif

#ifndef _WIN32_IE			// 允许使用特定于 IE 6.0 或更高版本的功能。
#define _WIN32_IE 0x0600	// 将此值更改为相应的值,以适用于 IE 的其他版本。值。
#endif

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS	// 某些 CString 构造函数将是显式的

// 关闭 MFC 对某些常见但经常可放心忽略的警告消息的隐藏
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC 核心组件和标准组件
#include <afxext.h>         // MFC 扩展

#include <afxdisp.h>        // MFC 自动化类

#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>		// MFC 对 Internet Explorer 4 公共控件的支持
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>			// MFC 对 Windows 公共控件的支持
#endif // _AFX_NO_AFXCMN_SUPPORT

#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type=‘win32‘ name=‘Microsoft.Windows.Common-Controls‘ version=‘6.0.0.0‘ processorArchitecture=‘x86‘ publicKeyToken=‘6595b64144ccf1df‘ language=‘*‘\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type=‘win32‘ name=‘Microsoft.Windows.Common-Controls‘ version=‘6.0.0.0‘ processorArchitecture=‘ia64‘ publicKeyToken=‘6595b64144ccf1df‘ language=‘*‘\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type=‘win32‘ name=‘Microsoft.Windows.Common-Controls‘ version=‘6.0.0.0‘ processorArchitecture=‘amd64‘ publicKeyToken=‘6595b64144ccf1df‘ language=‘*‘\"")
#else
#pragma comment(linker,"/manifestdependency:\"type=‘win32‘ name=‘Microsoft.Windows.Common-Controls‘ version=‘6.0.0.0‘ processorArchitecture=‘*‘ publicKeyToken=‘6595b64144ccf1df‘ language=‘*‘\"")
#endif
#endif

CreateThread.cpp

// CreateThread.cpp : implementation file
//

#include "stdafx.h"
#include "MulThreadTest.h"
#include "CreateThread.h"

extern UINT n;
// CCreateThread dialog

IMPLEMENT_DYNAMIC(CCreateThread, CDialog)

UINT CCreateThread::MulThreadFunc(LPVOID lpParam)							//线程函数,属于CCreateThread类的成员函数
{
	m_data* plp=(m_data *)lpParam;										//参数类型转化
	while(1)
	{
	  for(int pos=plp->m_pro.GetPos();pos<100;pos++)
		{
			(plp->m_pro).SetPos(pos);
			Sleep(100);
			if(plp->b)
			{
				ExitThread(0);
			}
		}
	  plp->m_pro.SetPos(0);
	}
	return 0;
}

CCreateThread::CCreateThread(CWnd* pParent /*=NULL*/)
	: CDialog(CCreateThread::IDD, pParent)
{
	check = FALSE;
}

CCreateThread::~CCreateThread()
{
}

void CCreateThread::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_PROGRESS1, m_d.m_pro);
}

BEGIN_MESSAGE_MAP(CCreateThread, CDialog)
	ON_BN_CLICKED(IDOK, &CCreateThread::OnBnClickedOk)
	ON_WM_PAINT()
END_MESSAGE_MAP()

// CCreateThread message handlers
void CCreateThread::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	m_d.b = check;
	if(!check)
	{
		pThread=AfxBeginThread(MulThreadFunc,&m_d,0,0,4);				//创建新的线程
		pThread->ResumeThread();										//开始执行
		GetDlgItem(IDOK)->SetWindowText(TEXT("暂停"));
		SetIcon(AfxGetApp()->LoadIcon(IDI_ICON2), FALSE);
	}
	else
	{
		GetDlgItem(IDOK)->SetWindowText(TEXT("继续"));
		SetIcon(AfxGetApp()->LoadIcon(IDI_ICON3), FALSE);
	}
	check = !check;
}

void CCreateThread::OnPaint()
{
	CPaintDC dc(this); // device context for painting
	// TODO: Add your message handler code here
	// Do not call CDialog::OnPaint() for painting messages
	CString showwin;
	showwin.Format(_T("Thread: %d"),n);
	SetWindowText(showwin);
	SetIcon(AfxGetApp()->LoadIcon(IDI_ICON4), FALSE);
}

MulThreadTest.cpp

// MulThreadTest.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "MulThreadTest.h"
#include "MulThreadTestDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMulThreadTestApp

BEGIN_MESSAGE_MAP(CMulThreadTestApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

// CMulThreadTestApp 构造

CMulThreadTestApp::CMulThreadTestApp()
{
	// TODO: 在此处添加构造代码,
	// 将所有重要的初始化放置在 InitInstance 中
}

// 唯一的一个 CMulThreadTestApp 对象

CMulThreadTestApp theApp;

// CMulThreadTestApp 初始化

BOOL CMulThreadTestApp::InitInstance()
{
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();

	AfxEnableControlContainer();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

	CMulThreadTestDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: 在此处放置处理何时用“确定”来关闭
		//  对话框的代码
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: 在此放置处理何时用“取消”来关闭
		//  对话框的代码
	}

	// 由于对话框已关闭,所以将返回 FALSE 以便退出应用程序,
	//  而不是启动应用程序的消息泵。
	return FALSE;
}

MulThreadTestDlg.cpp

// MulThreadTestDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "MulThreadTest.h"
#include "MulThreadTestDlg.h"
#include "CreateThread.h"
#include "NewWinThread.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMulThreadTestDlg 对话框

UINT n=0;

CMulThreadTestDlg::CMulThreadTestDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMulThreadTestDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
}

void CMulThreadTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CMulThreadTestDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDOK, &CMulThreadTestDlg::OnBnClickedOk)
END_MESSAGE_MAP()

// CMulThreadTestDlg 消息处理程序

BOOL CMulThreadTestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CMulThreadTestDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标显示。
//
HCURSOR CMulThreadTestDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CMulThreadTestDlg::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	//CCreateThread *pDlg;
	//pDlg = new CCreateThread;
	//pDlg->Create(IDD_DIALOG1);								//创建非模态对话框
	//pDlg->ShowWindow(SW_SHOW);								//显示对话
	n++;
	CWinThread *pthread=AfxBeginThread(RUNTIME_CLASS(CNewWinThread));
}

NewWinThread.cpp

// NewWinThread.cpp : implementation file
//

#include "stdafx.h"
#include "MulThreadTest.h"
#include "NewWinThread.h"
#include "CreateThread.h"

// CNewWinThread

IMPLEMENT_DYNCREATE(CNewWinThread, CWinThread)

CNewWinThread::CNewWinThread()
{
}

CNewWinThread::~CNewWinThread()
{
}

BOOL CNewWinThread::InitInstance()
{
	// TODO:  perform and per-thread initialization here
	CCreateThread *pDlg;
	pDlg = new CCreateThread;
	pDlg->Create(IDD_DIALOG1);								//创建非模态对话框
	pDlg->ShowWindow(SW_SHOW);								//显示对话
	return TRUE;
}

int CNewWinThread::ExitInstance()
{
	// TODO:  perform any per-thread cleanup here
	delete this;
	return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CNewWinThread, CWinThread)
END_MESSAGE_MAP()

// CNewWinThread message handlers

stdafx.cpp

// stdafx.cpp : 只包括标准包含文件的源文件
// MulThreadTest.pch 将作为预编译头
// stdafx.obj 将包含预编译类型信息

#include "stdafx.h"

本程序对线程创建做了一些控制,可以很直观的了解线程创建和销毁的过程,若有不足,还请批评指正!





时间: 2024-11-10 00:59:43

C++ 多线程编程总结的相关文章

多线程编程核心技术总结(读周志明书籍的总结)

多线程编程核心技术总结 1.Java多线程基本技能 1.1进程和线程的概念: 进程是独立的程序,线程是在进程中独立运行的子任务. 1.2使用多线程 1.2.1实现方法:继承Thread类,重写Runnable接口. 1.2.2线程安全问题:并发修改公共的实例变量,i++,i-- 1.3线程Thread类的一些方法: currentThread() 放回代码段正在被那个线程调用 isAlive() 判断线程是否处于活动状态 sleep() 使得当前线程退出CPU片段,等待获取锁 1.4停止线程 1

Java基础知识—多线程编程(五)

概述 Java 给多线程编程提供了内置的支持.一个多线程程序包含两个或多个能并发运行的部分.程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径.使用多线程也是为了充分的利用服务器资源,提高工作效率. 线程生命周期 线程是一个动态执行的过程,它也有一个从产生到死亡的过程. 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 就绪状态: 当线程对象调用了start()方法之后,该

第73课 Qt中的多线程编程

1. QThread类 (1)QThread是一个跨平台的多线程解决方案 (2)QThread以简洁易用的方式实现多线程编程 2. QThread中的关键成员函数 (1)virtual void run() :线程函数,用于定义线程功能(执行流). (2)void start():启动函数,将线程入口地址设置为run函数.启动线程,新线程开始执行run函数. (3)int exec():进入事件循环,直至调用exit().返回线程退出事件循环的返回码. (4)void terminate():强

多线程编程(进程和线程)

多线程编程(进程和线程) 1.进程:指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程可以启动多个线程. 2.线程:指程序中一个执行流程,一个进程中可以运行多个线程. 一.创建线程(两种方式) 二.线程的5种状态( New,Runnable,Running,Block,Dead ): 三.线程的优先级 四.守护线程 /精灵线程/后台线程 五.方法 六.同步代码锁(synchronized) 一.创建线程(两种方式): 方式1:采用继承Thread的方法 第一,继承 Thre

多线程编程基础知识

多线程编程基础知识 http://www.cnblogs.com/cy163/archive/2006/11/02/547428.html 当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的出现,对提高软件的并行性有着重要的意义.现在的大型应用软件无一不是多线程多任务处理,单线程的软件是不可想象的.因此掌握

iOS多线程编程

1. 进程,线程, 任务 进程:一个程序在运行时,系统会为其分配一个进程,用以管理他的一些资源. 线程:进程内所包含的一个或多个执行单元称为线程,线程一般情况下不持有资源,但可以使用其所在进程的资源. 任务:进程或线程中要做的事情. 在引入线程的操作系统中,通常把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位. 线程比进程更小,对其调度的开销小,能够提高系统内多个任务的并发执行程度. 一个程序至少有一个进程,一个进程至少有一个线程.一个程序就是一个进程,而一个程序中的多个任

多线程编程1-NSThread

前言 每个iOS应用程序都有个专门用来更新显示UI界面.处理用户触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将那些耗时的操作放到另外一个线程中去执行,多线程编程是防止主线程堵塞,增加运行效率的最佳方法. iOS中有3种常见的多线程编程方法: 1.NSThread 这种方法需要管理线程的生命周期.同步.加锁问题,会导致一定的性能开销 2.NSOperation和NSOperationQueue 是基于OC

Android多线程编程(一)——多线程基础

什么是进程 一个进程是一个独立(self contained)的运行环境,它可以看作一个程序或者一个应用. 什么是线程 而线程是进程中执行的一个任务,Java运行环境是一个包含了不同累和程序的单一进程.线程可以被称为轻量级进程.线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源. Android线程 Android的线程,实际上和Java的多线程编程并没有什么本质上的不同.当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如

《Java多线程编程核心技术》推荐

写这篇博客主要是给猿友们推荐一本书<Java多线程编程核心技术>. 之所以要推荐它,主要因为这本书写得十分通俗易懂,以实例贯穿整本书,使得原本抽象的概念,理解起来不再抽象. 只要你有一点点Java基础,你就可以尝试去阅读它,相信定会收获甚大! 博主之前网上找了很久都没完整pdf电子版的,只有不全的试读版,这里博主提供免费.清晰.完整版供各位猿友下载: http://download.csdn.net/detail/u013142781/9452683 刚刚已经提到,<Java多线程编程核

Java多线程编程— 概念以及经常使用控制

多线程能满足程序猿编写很有效率的程序来达到充分利用CPU的目的,由于CPU的空暇时间可以保持在最低限度.有效利用多线程的关键是理解程序是并发运行而不是串行运行的.比如:程序中有两个子系统须要并发运行,这时候就须要利用多线程编程. 线程的运行中须要使用计算机的内存资源和CPU. 一.    进程与线程的概念 这两者的概念,这里仅仅给出自己狭隘的理解: 进程:进程是一个独立的活动的实体,是系统资源分配的基本单元. 它能够申请和拥有系统资源. 每一个进程都具有独立的代码和数据空间(进程上下文). 进程