现在的位置: 首页 > 综合 > 正文

多线程学习系列之——一个简单的多线程程序

2013年12月08日 ⁄ 综合 ⁄ 共 2366字 ⁄ 字号 评论关闭
文章目录

 

多线程学习系列之——一个简单的多线程程序

 

 

一、 首先看下什么是进程,什么是线程?

1.  进程

进程是资源申请、调度和独立运行的单位,它使用系统中的运行资源。进程通常被定义为一个正在运行程序的实例,是一个程序在其自身的地址空间中的一次执行活动。

进程有两部分组成:

(1)内核对象,有操作系统来管理

内核对象是系统用来存放进程的统计信息的地方。内核对象是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息。

(2)地址空间

它包含所有可执行模块或DLL模块的代码和数据。另外,它也包含动态内存分配的空间,例如线程的栈和堆分配的空间。

进程从来不执行任何东西,它只是线程的容器。若要使进程完成某项操作,它必须拥有一个在它环境中运行的线程,此线程负责执行包含在进程地址空间中的代码。

也就是说:真正完成代码执行的是线程,而进程是线程的容器,或者说是线程的执行环境。

系统赋予每个进程独立的虚拟地址空间,对于32位进程来说,这个地址空间是4GB

2.  线程

线程的组成:

(1) 线程的内核对象。操作系统用线程的内核对象对线程进行管理,内核对象也是系统用来存放线程统计信息的地方。

(2) 线程栈。线程栈用于维护线程在执行代码时需要的所有函数参数和局部变量。

线程总是在某个进程环境中创建的,线程只有一个内核对象和一个栈,保留的记录很少,因此所需要的内存也很少。

二、 单线程程序与多线程程序

对单线程程序来说,在进程的地址空间中只有一个线程在运行。

多线程程序,在进程地址空间中有多个线程,其中有一个是主线程。

在单CPU的情况下,某一时刻只能有一个线程在运行,那么为什么还要写多线程呢?

(1)对进程的创建来说,系统要为进程分配私有的4GB的虚拟地址空间,当然它占用的资源就比较多,而多线程程序,多线程是共享同一个进程的地址空间,占有资源比较少

(2)当进程间切换时,需要交换整个地址空间,而线程间的切换只是执行环境的改变,效率比较高。

三、  进程与线程间的区别:

进程是程序的一次执行。线程可以理解为进程执行中的一个程序片段。在一个多任务环境中下面的概念可以帮助我们理解两者的差别。

进程间是独立的,这表现在内存空间、上下文环境上;线程运行在进程空间内。一般来讲,进程无法突破进程边界存取其他进程内的存储空间;而线程由于处于进程空间内,所以同一进程所产生的线程共享同一内存空间。

同一进程中的两段代码不能够同时执行,除非引入线程。

线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。线程占有的资源少于进程所占有的资源。进程和线程都可以有优先级。

四、  进程间通信是如何实现的?

常见的进程间通信方式有:信号、信号量、消息队列、共享内存。

所谓进程间通信就是不同进程之间进行一些“接触”。

信号和信号量都可以实现同步和互斥,但是信号是使用信号处理器来进程的,信号量是使用PV操作来实现的。消息队列是一种高级的进程间通信的方法,它可以在进程间传送message,一个消息队列可以被多个进程所共享。

五、  线程间通信是如何实现的?

临界区、互斥量、信号量、事件

windows编程中互斥器和临界区类似,他们的区别是:互斥器可以用于进程间互斥,临界区是线程间的互斥。

六、 最后我们来用多线程来演示下火车站售票系统模拟程序

在实习买票过程中呢,多个人可以同时购买火车票,我们下面编写2个线程,由主线程创建的两个线程(线程1和线程2)负责销售火车票。

代码:

#include <Windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI Fun1(LPVOID lpParameter);

DWORD WINAPI Fun2(LPVOID lpParameter);


int index = 0;
int tickets = 100;   //全局变量tickets用来表示销售的剩余票数
int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hThread1;
 HANDLE hThread2;
 //创建线程
 hThread1 = CreateThread(NULL,0,Fun1,NULL,0,NULL);
 //4个参数的意思分别为:使线程使用默认的安全性、让新线程采用与调用线程一样的栈大小、指定线程的入口函数地址、
 //线程创建标记,0表示让线程一旦创立就运行、新线程的ID,不需要的话为null
    hThread2 = CreateThread(NULL,0,Fun2,NULL,0,NULL);
 CloseHandle(hThread1);  //调用CloseHandle将此线程的句柄关闭,关闭句柄时,系统会递减该线程内核对象的使用计数。
 CloseHandle(hThread2);
 Sleep(4000); //让线程暂停运行4s
    system("pause");
 return 0;
}

//线程1入口函数
DWORD WINAPI Fun1(LPVOID lpParameter)
{
 while (TRUE)
 {
  if (tickets > 0)
  {
   Sleep(1);
   cout<<"thread1 sell ticket : "<<tickets--<<endl;
  }
  else
  {
   break;
  }
 }
 return 0;
}

//线程2的入口函数
DWORD WINAPI Fun2(LPVOID lpParameter)
{
 while (TRUE)
 {
  if (tickets > 0)
  {
   Sleep(1);
   cout<<"thread2 sell ticket : "<<tickets--<<endl;
  }
  else
  {
   break;
  }
 }
 return 0;
}

运行结果:

 

参考资料:

《vc++++深入详解》 电子工业出版社 孙鑫 P557-570

《程序员面试宝典》 电子工业出版社 欧立齐 P253-257

 

 

抱歉!评论已关闭.