C++多线程编程入门
(2011-10-08 18:01:42),转载自 http://blog.sina.com.cn/s/blog_4b4409c30100vmi2.html 标签: 杂谈 |
第1节
解为何当年IBM预测“全球只要有4台计算机就够了”。
系统中是执行工作的基本单元。进程是包含程序指令和相关资源的集合。每个进程和其他进程一起参与调度,竞争CPU,内存等系统资源。每次进程切换,都存在进程资源的保存和恢复动作,这称为上下文切换。
进程间通信要求复杂的系统级实现。
第2节
本节介绍如下内容:线程状态、线程运行环境、线程类定义
示例程序:线程类的Windows和Unix实现
线程状态
线程环境
线程存在于进程之中。进程内所有全局资源对于内部每个线程均是可见的。
进程内典型全局资源有如下几种:
线程内典型的局部资源有:
一个进程发起之后,会首先生成一个缺省的线程,通常称这个线程为主线程。C/C++程序中主线程就是通过main函数进入的线程。由主线程衍生的线程称为从线程,从线程也可以有自己的入口函数,作用相当于主线程的main函数。
为了更好的理解上述概念,下面通过具体代码来详细说明。
线程类接口定义。一个线程类无论具体执行什么任务,其基本的共性无非就是: 创建并启动线程、停止线程。另外还有就是能睡,能等,能分离执行(有点拗口,后面再解释)。
将线程的概念加以抽象,可以为其定义如下的类:
文件 thread.h
Thread::start()函数是线程启动函数,其输入参数是无类型指针。
Thread::stop()函数中止当前线程。
Thread::sleep()函数让当前线程休眠给定时间,单位为秒。
Thread::run()函数是用于实现线程类的线程函数调用。
Thread::detach()和thread::wait()函数涉及的概念略复杂一些。在稍后再做解释。
Thread类是一个虚基类,派生类可以重载自己的线程函数。下面是一个例子。
示例程序
#ifndef __THREAD__H_
#define __THREAD__H_
class Thread
{
public:
Thread();
virtual ~Thread();
int start (void * = NULL);
void stop();
void sleep (int);
void detach();
void * wait();
protected:
virtual void * run(void *) = 0;
private:
//这部分win和unix略有不同,先不定义,后面再分别实现。
//顺便提一下,我很不习惯写中文注释,这里为了更明白一
//点还是选用中文。
…
};
#endif
代码写的都不够精致,暴力类型转换比较多,欢迎有闲阶级美化,谢过了先。
文件create.h
#ifndef __CREATOR__H_
#define __CREATOR__H_
#include <stdio.h>
#include "thread.h"
class Create: public Thread
{
protected:
void * run(void * param)
{
char * msg = (char*) param;
printf ("%s\n", msg);
//sleep(100); 可以试着取消这行注释,看看结果有什么不同。
printf("One day past.\n");
return NULL;
}
};
#endif
然后,实现一个main函数,来看看具体效果:
文件Genesis.cpp
#include <stdio.h>
#include "create.h"
int main(int argc, char** argv)
{
Create monday;
Create tuesday;
printf("At the first God made the heaven and the earth.\n");
monday.start("Naming the light, Day, and the dark, Night, the first day.");
tuesday.start("Gave the arch the name of Heaven, the second day.");
printf("These are the generations of the heaven and the earth.\n");
return 0;
}
编译运行,程序输出如下:
At the first God made the heaven and the earth.
These are the generations of the heaven and the earth.
令人惊奇的是,由周一和周二对象创建的子线程似乎并没有执行!这是为什么呢?别急,在最后的printf语句之前加上如下语句:
monday.wait();
tuesday.wait();
重新编译运行,新的输出如下:
At the first God made the heaven and the earth.
Naming the light, Day, and the dark, Night, the first day.
One day past.
Gave the arch the name of Heaven, the second day.
One day past.
These are the generations of the heaven and the earth.
为了说明这个问题,需要了解前面没有解释的Thread::detach()和Thread::wait()两个函数的含义。
这种方式常用在线程数较多的情况,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是很困
难或者不可能的。所以在并发子线程较多的情况下,这种方式也会经常使用。
缺省情况下,创建的线程都是可会合的。可会合的线程可以通过调用detach()方法变成相分离的线程。但反向则不行。
UNIX实现
文件 thread.h
#ifndef __THREAD__H_
#define __THREAD__H_
class Thread
{
public:
Thread();
virtual ~Thread();
int start (void * = NULL);
void stop();
void sleep (int);
void detach();
void * wait();
protected:
virtual void * run(void *) = 0;
private:
pthread_t handle;
bool started;
bool detached;
void * threadFuncParam;
friend void * threadFunc(void *);
};
//pthread中线程函数必须是一个全局函数,为了解决这个问题
//将其声明为静态,以防止此文件之外的代码直接调用这个函数。
//此处实现采用了称为Virtual friend function idiom 的方法。
Static void * threadFunc(void *);
#endif
文件thread.cpp
#include <pthread.h>
#include <sys/time.h>
#include “thread.h”
static void * threadFunc (void * threadObject)
{
Thread * thread = (Thread *) threadObject;
return thread->run(thread->threadFuncParam);
}
Thread::Thread()
{
started = detached = false;
}
Thread::~Thread()
{
stop();
}
bool Thread::start(void * param)
{
pthread_attr_t attributes;
pthread_attr_init(&attributes);
if (detached)
{
}
threadFuncParam = param;
if (pthread_create(&handle, &attributes, threadFunc, this) == 0)
{
}
pthread_attr_destroy(&attribute);
}
void Thread::detach()
{
if (started && !detached)
{
}
detached = true;
}
void * Thread::wait()
{
void * status = NULL;
if (started && !detached)
{
}
return status;
}
void Thread::stop()
{
if (started && !detached)
{
}
}
void Thread::sleep(unsigned int milliSeconds)
{
timeval timeout = { milliSeconds/1000, millisecond00};
select(0, NULL, NULL, NULL, &timeout);
}
Windows实现
文件thread.h
#ifndef _THREAD_SPECIFICAL_H__
#define _THREAD_SPECIFICAL_H__
#include <windows.h>
static unsigned int __stdcall threadFunction(void *);
class Thread {
public:
protected:
private:
};
#endif
文件thread.cpp
#include "stdafx.h"
#include <process.h>
#include "thread.h"
unsigned int __stdcall threadFunction(void * object)
{
}
Thread::Thread()
{
}
Thread::~Thread()
{
}
int Thread::start(void* pra)
{
}
//wait for current thread to end.
void * Thread::wait()
{
}
void Thread::detach()
{
if (started && !detached)
{
}
detached = true;
}
void Thread::stop()
{
}
void Thread::sleep(unsigned int delay)
{
}
小结
本节的主要目的是帮助入门者建立基本的线程概念,以此为基础,抽象出一个最小接口的通用线程类。在示例程序部分,初学者可以体会到并行和串行程序执行的差异。有兴趣的话,大家可以在现有线程类的基础上,做进一步的扩展和尝试。如果觉得对线程的概念需要进一步细化,大家可以进一步扩展和完善现有Thread类。想更进一步了解的话,一个建议是,可以去看看其他语言,其他平台的线程库中,线程类抽象了哪些概念。比如Java, perl等跨平台语言中是如何定义的,微软winapi到dotnet中是如何支持多线程的,其线程类是如何定义的。这样有助于更好的理解线程的模型和基础概念。
本文至此,如果自己动手改改,试一些例子,对多线程程序应该多少有一些感性认识了。刚开始只要把基本概念弄懂了,后面可以一步一步搭建出很复杂的类。不过刚开始不要贪多,否则会欲速则不达,越弄越糊涂。最后,大家见仁见智吧,我在此起到抛砖引玉的作用就很开心了,呵呵。另外文本编辑器的原因,代码如果编译不过,可能需要
把标点符号从中文换成英文。