今天决定写一个linux下的多线程系列文章。本人也是对多线程也是长期以来就有耳闻,但一直没有下手,直到最近没办法了所以决定写此系列文章。作为初学者,对多线程理解定存在理解不够深入之处,错误在所难免,如有错误请批评指正。但本文保证以自己为范本,从解决最基本问题做起,让每一位初学者和我一起解决问题。
多线程系列特色:
1)、直接上完整代码,尽量保证每一个代码完整;
2)、贴代码在Linux Shell下调试结果;
3)、每一个步骤精细讲述;
本文内容概要:
一、搭建Linux多线程开发环境;
二、进程、线程简介;
三、线程介绍;
Start:
一、搭建Linux多线程开发环境;
一般情况下,我们都是用Windows系统,当然在Windows下也可开发多线程,但不是本文的目的。既然是在Linux下开发多线程,肯定要搭建好Linux环境。目前知道3种方案:
方案一:装双系统,用UltraISO制作Linux系统盘;本文直接给链接http://jingyan.baidu.com/article/ff411625ac846712e4823737.html;
方案二:安装虚拟机,然后在虚拟机上安装Linux系统;本文利用的虚拟机是VMware Workstation,从下图可以看出。虚拟机其实就是一个可以运行在Windows上的软件,打开虚拟机后在虚拟机上安装系统就可以了,从下面图片可以看出已经在VMware上安装了Windows7 64位系统和Linux系统Ubuntu。虚拟机的下载和安装网上都有。
方案三:现在阿里云、腾讯云之类的可以直接租用Linux系统,一般刚注册可以短暂使用,除非你付费可以一直使用。这里示意性的给出阿里云链接。
https://www.aliyun.com/?utm_medium=text&utm_source=bdbrand&utm_campaign=bdbrand&utm_content=se_32492
本人采用方案二,在虚拟机VMware上安装了Ubuntu系统.友情提示:由于VMware上又安装了系统,所以耗用系统资源比较多,建立自己电脑是Windows64位的并且内存在8G以上。若是安装在Win32上可能会导致系统很卡,到时候很感觉一定很不爽。
二、进程、线程简介;
1、进程和线程
1.1)进程:
官方表述:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。[
山东枣普表述:
在我们使用的应用软件都是以进程的形式进行运行的。为了直观感受一下,在Windows上按下Ctrl+Alt+Delete出现Windows任务管理器,如下图所示。点开进程,可以看到当前电脑运行的一些进程,点击性能可以看到下图,本人的计算机进程数74,线程数是1317.
1.2)线程:
本人列写了其他的一些表述,以达到让读者更全面了解。
官方表述1:
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
官方表述2:
线程是指运行中的程序的调度单位。一个线程指的是进程中一个单一顺序的控制流,也被称为轻量级线程。它是系统独立调度和分配的基本单位。同一进程中的多个线程将共享该系统中的全部系统资源,比如文件描述符和信号处理等。一个进程可以有很多线程,每个线程并行执行不同的任务。
官方表述3:
线程是包含在进程内部的顺序执行流,是进程中实际运作单位,也是操作系统能够进行调度的最小单位,一个进程中可以并发多条线程,每条线程并行执行不同的任务。
山东枣普表述:
主要明白一点就是一个进程包含多个线程。举个栗子:线程就是小混混,许多个小混混一定有个老大。老大就是进程。老大管理自己的小混混兄弟。
1.3)线程和进程的关系
1> 一个线程只能属于一个进程,但是一个进程可以有多个线程,但至少有一个主线程。
2> 同一进程的所有线程共享该进程的所有资源。
3> 线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
4> 进程是拥有资源的一个独立单位,线程不拥有系统资源,但是可以访问隶属于进程的资源
1.4)多线程编程的优势
1> 方便的通信和数据交换,同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其他线程所用
2> 更高效的利用CPU,提高应用程序的响应。
三、线程介绍
1、线程常用函数介绍
1.2)线程创建函数
函数pthread_create()用来创建线程。头文件为pthread.h。
函数声明在/usr/include/pthread.h.
Shell指令:vim /usr/include/pthread.h.
上述指令的意义:打开pthread.h文件,Vim工具可以理解为Windows下的记事本。
系统中可能需要安装Vim,安装指令如下:sudo apt-get install vim,然后回车,输入一下自己开机密码就可以了。
在命令行模式下,执行如下指令
Shell指令:/pthread_create
上述指令的意思是从Vim打开的phread.h文件中查找pthread_create,按n查找下一处,查找效果如下图
从上图244-247行可以看到pthread_create函数。
顺便理解一下244行的extern:
extern是计算机语言中的一个函数,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义,另外,extern也可用来进行链接指定。
下面介绍一下pthread_create()函数的四个参数的意思。
第一个参数:
pthread_t定义在/usr/include/bits/pthreadtypes.h中
typedef unsigned long int pthread_t;
顺便解释一下typedef:typedef是在计算机编程语言中用来为复杂的声明定义简单的别名,与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中。其实就是说typedef是为了给给usigned long int 起了个别的名字叫pthread_t.
_restrict用来提高编译效率。 newthread用来存储线程ID,当你申请一个线程,这个线程ID就用这个参数来表示。
第二个参数:
pthread_attr_t定义在/usr/include/bits/pthreadtypes.h中;
我的Ubuntu系统pthreadtypes.h路径与上述不符合,如果找不到可以locate pthreadtypes.h;然后利用Vim打开。
从上图第60行可以找到pthread_t;
63-67行定义了pthread_attr_t;
pthread_attr_t代表线程的属性,线程的属性有作用域(scope)、栈尺寸(stack size)、栈地址(stack address)、优先级(priority)、分离的状态(detached state)、调度策略和参数(scheduling policy and parameters)。NULL则代表默认属性,默认的属性为非绑定、非分离、缺省1M的堆栈、与父进程同样级别的优先级。
第三个参数:
该参数代表线程运行函数的起始地址。
第四个参数:
既然第三个参数是线程函数的起始地址,那么线程函数需要参数啊,这里的第四个参数就是线程函数传入的参数。如果需要传入多个参数,那么通常以结构体形式传入。
写的太累了,后续系列写代码吧,本文先不贴代码了。