什么是线程:有时也被成为轻量级进程,是程序执行流的最小单元。
一个标准的线程是由线程ID,当前指令指针(PC)、寄存器集合和堆栈组成。
一个进程是由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段的堆等)及一些进程级的资源(如打开文件和信号)
多个线程可以互不干扰的并发执行,并共享进程的全局变量和堆的数据;
线程的访问权限
线程的访问权限非常自由,可以访问进程内存里的所有数据;
线程调度与优先级
单处理器对应多线程:操作系统让这些多线程轮流执行,每次仅执行一小段时间(通常是几十秒),这样每个线程“看起来”就像是在同时执行;这样的一个处理器上不断切换线程的操作成为“线程调度”
线程调度中的三种状态:
(1):运行,此时线程正在运行
(2):就绪,此时线程可以立即运行,但CPU已被占用
(3):等待,此时线程正在等待某一事件发生,无法执行
每当一个程序离开运行状态,调度系统就会选择一个就绪的线程运行;一个在等待状态的线程事件发生以后进入就绪状态。
在优先级调度的情况下,线程优先级的改变一般有三种方式:
用户指定优先级;
根据进入等待状态的频繁程度提升或降低优先级;
长时间得不到执行而被提升优先级;
Linux的多线程
在Linux下,可以用以下三个方法创建一个新的任务:
(1)fork:复制当前进程
(2)exec:使用新的可执行映像覆盖当前可执行映像
(3)clone:创建子进程,并从指定位置开始执行;
fork:
pid_t pid;
if(pid==fork()){…}
在fork调用以后,新的任务启动并和本任务一起从fork函数返回,但不同的是本任务的fork将返回新任务的pid,而新任务的fork将返回0;
fork产生新任务的速度非常快,因为fork不复制原任务的内存空间,而是和原任务一起共享一个写时拷贝的内存空间;
所谓写时拷贝:指的是两个任务可以同时自由地读取内存,但任意一个任务试图对内存进行修改时,内存就会复制一份提供给修改方单独使用,以免影响到其他的任务使用;
fork只能够产生本任务的镜像,因此必须使用exec配合才能启动别的新任务,exec可以用新的可执行映像替代当前的可执行映像,因此在fork产生了一个新任务之后,新任务可以调用exec来执行新的可执行文件;
头文件都定义在pthread.h中
创建一个线程:#include
int pthread_create (pthread_t *thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void*arg)
thread参数是新线程的标识符,后续的pthread_*函数通过它来引用新线程;
attr参数用于设置新线程的属性,给它传递NULL表示使用默认线程属性;
Start_routine 和arg参数分别制定新线程将运行的函数及参数;
pthread_create成功时返回0,失败时返回错误码;
结束一个线程:void pthread_exit(void *retval)
函数通过retval参数向线程的回收者传递其退出信息;
线程安全:
多线程程序处于一个多变的环境当中,可访问的全局变量和堆数据都可能随时被其他的线程改变;
手段:同步与锁
原子的:单指令操作称为原子的,无论如何,单条指令的执行是不会被打断的;
为了避免多个线程同时读写一个数据而产生不可预料的后果,我们要将各个线程对同一个数据的访问同步(所谓同步,就是在一个线程访问数据未结束时,其他线程不得对同一个数据进行访问),因此,对数据的访问被原子化;
同步的常见方法:(信号量、互斥量、临界区,读写锁、条件变量)
锁:每一个线程在访问数据或资源时首先试图获取锁,并在访问结束后释放锁;
信号量:线程访问资源的时候首先获取信号量;
操作如下:
(1)将信号量的值减1;
(2)如果信号量的值小于0,则进入等待状态;否则继续执行;
访问完资源之后,线程释放信号量;
(3)将信号量的值加1;
(4)如果信号量的值小于1,唤醒一个等待中的线程;
互斥量&&信号量
同:资源仅同时允许一个线程访问;
异:信号量在整个系统中,可以被任意线程获取并释放,也就是说,同一个信号量可以被系统中的一个线程获取后,另一个线程释放;
而互斥量要求哪个线程获取了互斥量,哪个线程就要负责释放这个锁,其他线程越俎代庖去释放互斥量是无效的;
临界区:是比互斥量更加严格的同步手段
把临界区的锁的获取称为进入临界区;
而把锁的释放称为离开临界区。
区别(与信号量和互斥量)
互斥量和信号量在系统的任何进程里都是可见的;
也就是说一个进程创建了一个互斥量或信号量,另一个进程试图去获取该锁是合法的;
临界区的作用范围仅限于本进程,其他的进程无法获取该锁
读写锁:
两种方式:共享的 独占的
当锁出于自由状态时,试图以任何一种方式获取锁都能成功,并将锁置于对应的状态;(如上图)
条件变量:作为同步的一种手段,作用类似于一个栅栏;
对于条件变量,线程有两种操作:
(1)首先线程可以等待条件变量,一个条件变量可以被多个线程等待;
(2)线程可以唤醒条件变量,此时某个或所有等待此条件变量的线程都会被唤醒并继续支持;
(也就是说,使用条件变量可以让许多现车鞥一起等待某个事件的发生,当事件发生时,所有线程可以一起恢复执行)。
相关文章:
以上是java学习:什么是线程?最详细的解释的详细内容。更多信息请关注PHP中文网其他相关文章!