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

 

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

 

 

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

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

 

 

多线程 求质数 返回数组中的最大值 bool isPrime(long x) { if (x <= 1) return false; if (x == 2) return true; for (long i = 2; i <= ceil(sqrt((long double)x));i++) if (x%i == 0) return false; return true; } DWORD WINAPI findPrime(void* p) { long result=0; int l = stc(p)->lower, u = stc(p)->uper; int t_id=GetCurrentThreadId(); for (int i = l; i <= u;i++) if (isPrime(i)) { result++; } DWORD dReturn = WaitForSingleObject(mutex_mul_result_h, INFINITE); mul_result += result; ReleaseMutex(mutex_mul_result_h); //EnterCriticalSection(&gCRITICAL_SECTION_Printf); //printf("%d,%d,%d,%d\n", l, u, result,t_id); //fflush(stdout); //LeaveCriticalSection(&gCRITICAL_SECTION_Printf); return 0; } //dispatcher void dispatch() { DWORD Status; timer tm; tm.start(); //srand(time(NULL)); long step = STEP;//ceil(double(TEST/10)); handlenum = 0; for (int i = 1; i <= TEST;) { i += step; handlenum++; } handle_array=new HANDLE[handlenum]; Thread_id = new DWORD[handlenum ]; arg = new FP_ARG[handlenum]; InitializeCriticalSection(&gCRITICAL_SECTION_Printf); mutex_mul_result_h = CreateMutex(NULL, false, mutex_mul_result); handlenum = 0; for (int i = 1; i <= TEST;) { arg[handlenum].lower = i; arg[handlenum].uper = (i + step-1>TEST) ? TEST : i + step-1; handle_array[handlenum]=(HANDLE)CreateThread(NULL, 0, findPrime, &arg[handlenum], 0, &Thread_id[handlenum]); /*EnterCriticalSection(&gCRITICAL_SECTION_Printf); printf("lower:%d uper:%d thread_id:%d\n", arg[handlenum].lower, arg[handlenum].uper,Thread_id[handlenum]); LeaveCriticalSection(&gCRITICAL_SECTION_Printf);*/ i += step; handlenum++; } tm.stop(); Sleep(1000); printf("there are %d threads\n", handlenum); printf("the multithreads use %f msc\n", tm.read()); } //the number of 1-1000000 Primenumber void s_finePrime() { timer tm; long result = 0; tm.start(); for (int i = 1; i <= TEST; i++) if (isPrime(i)) result++; tm.stop(); printf("Single thread result is %d\n", result); printf("Single thread use %f msc\n", tm.read()); } int _tmain(int argc, _TCHAR* argv[]) { dispatch(); WaitForMultipleObjects(handlenum, handle_array, true, INFINITE);//不起作用 printf("the multithreads reslut is %d\n", mul_result); CloseHandle(mutex_mul_result_h); DeleteCriticalSection(&gCRITICAL_SECTION_Printf); s_finePrime(); system("pause"); return 0; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值