线程、进程的概念与关系以及线程的创建

线程、进程的概念与关系以及线程的创建

1、前言

线程对于程序开发而言是一个很重要的概念,由于在实际的项目开发过程中经常会用到线程、多线程技术,所以就对线程的概念与使用进行一下简单的总结,并对线程相关的概念如程序、进程、线程同步、线程池等概念也会进行相关的介绍。由于不同的环境、平台会用到不同的线程开发技术,所以在本文章中也会对其他不同平台的线程技术进行简单的介绍。由于内容较多,所以具体更新时间不定。

2、概述

在使用线程技术之前,需要先介绍一下进程的概念,然后说明一下进程与线程的不同与联系,以免造成混淆。

2.1、进程

说到进程,我们可能首先会想到程序。因为对于开发人员来说,程序是可见的,即是最终生成的可执行 *.exe 文件,而进程是看不见的。所以大部分人也就会认为程序就是进程。这样理解是不正确的。

程序是计算机指令的集合,它以文件的形式存储在磁盘上,使我们经常见到的*.exe程序;而进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动。由此也可以看出,程序与进程的不同。程序是“静止”的,而进程是“活动”的,进程是在地址空间中执行程序指令集合的一次过程。

程序可以有多个进程。比如说,经常使用的记事本程序,我们能够打开多个记事本文件,每一个记事本文件都是一个执行中的进程。

进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,所以,程序不占用系统的运行资源。

2.2、进程的组成

进程由两部分组成:

(1)、操作系统用来管理进程的内核对象

内核对象是系统用于存储关于进程的统计信息的地方。内核对象是操作系统内部分配的一个内存块,用于存储、维护该对象的各种信息。内核对象的数据结构只能被内核访问并使用,所以只能通过Windows提供的一个系统函数对内核对象进行操作。

(2)、地址空间

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

系统为每一个进程都分配了独立的虚拟地址空间。对于32位系统来说,它的寻址范围为2的32次方,即4GB,所以对于32位进程来说,分配的虚拟地址空间大小为4GB。

2.3、进程与线程的关系

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

一个进程可以拥有多个线程,每个进程至少拥有一个线程。当创建一个进程时,操作系统会自动创建这个进程的第一个线程。当然我们可能感觉不到,因为这个第一个线程被称为主线程,main()函数或者WinMain()函数可以被当为该主线程的入口函数。然后就可在主线程中去完成其它线程的创建了。

3、线程

线程有两部分组成:

(1)、线程的内核对象

操作系统通过线程的内核对象对线程实施管理,同时内核对象也是系统用来存放线程统计信息的地方。

(2)、线程栈

当创建一个线程时,系统会为该线程分配一个线程内核对象。系统可已通过该内核对象对线程进行相关的操作。

线程总是在某个进程环境中差创建的。系统从进程的地址空间中分配内存,供线程的栈使用。新线程运行的进程环境与创建线程的环境相同。因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同进程中的其他线程的堆栈。这使得单个进程中多个线程能够非常容易的互相通信。

线程只有一个内核对象和一个栈,保留的记录很少,因此需要的内存也很少。由于线程需要的开销比进程少,因此在编程中进场采用多线程解决编程问题。

操作系统为每一个运行线程安排一定的CPU时间---时间片。系统通过一种循环的方式为线程提供时间片,线程在自己的时间片中运行,因为时间片很短,因此就会造成多个线程同时进行的错觉。如果在多CPU环境下,就会实现真正意义上的多线程同时运行。

3.1、线程的创建

在Windows环境下,线程的创建是通过系统API:CreatThread函数来完成的。

CreatThread函数声明如下:

HANDLE CreateThread(
 LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 线程的安全性属性,可以设置为NULL,使该线程使用默认安全属性
 DWOED dwStaticSize,  //设置线程的初始栈大小,即线程可以将多少地址空间用于它自己的栈,已字节为单位。可以设置为0,表示默认使用与调用函数的线程相同的栈空间大小
 LPTHREAD_START_ROUTINE lpStartAddress, //指向应用程序定义的该类型函数的指针,该函数将有新线程执行,表明新线程的起始地址
 LPVOID lpRarameter, //通过该参数给创建的新线程传递参数
 DWOED dwCreationFlags, //用于设置控制线程创建的附加标记。可以将值设为0,表示,线程创建之后就立即执行
 LPWORD lpThreadId  //该参数是一个返回值,用于接收线程ID,可以将值设为NULL,表示对线程ID不感兴趣
);

    其中,lpStartAddress表示为该线程的入口函数。入口函数的定义需遵照如下的声明形式:

DWORD WINAPI ThreadFun(LPVOID lpParameter);

该新线程入口函数有一个LPVOID类型的参数,并且返回值是DWORD类型。

线程创建实例如下所示:

DWORD WINAPI ThreadFun(LPVOID lp);
void main()
{
HANDLE hThread1;
hThread1 = CreateThread(NULL, 0, ThradFun, 0, NULL);
CloseHandle(hThread1);  //关闭线程
}
DWORD WINAPI ThreadFun(LPVOID lp)
{
***
return 0;
}

3.2、线程的同步

线程的同步。


猜你喜欢

转载自blog.csdn.net/bailang_zhizun/article/details/78338598