(一)初识线程与进程

来源:互联网 发布:grpc java实现 编辑:程序博客网 时间:2024/06/17 20:50

一、前言

    最近项目中用到多线程,问题背景是:有个数据采集设备,使用以太网进行通信,一旦建立以太网链接之后,该设备自己的内置程序就可以并行的循环接收多个类型的数据(也就是它自己有一个数据接收线程),那么现在我需要以一定的周期读取这些数据,并且保证这些数据是该设备最近一次读取的完整数据,因为设备接收并保存的数据是一个比较大的数据区段,它自身是用vector保存的,这就涉及到了对一段内存区域的同时读取操作,即设备自身在不停的写这个内存区域,而我自己的程序在不停的读这个区域,这就需要使用多线程同步技术来保证每次读取的数据都是最新的完整的数据,不能有设备写一半,然后我的程序读一半的情况。这也就是多线程编程中的“生产者——消费者”问题。


二、理解线程与进程

    其实说到线程,自然也要解释什么是进程,说到进程又要联系到程序(即你编辑完成,并能运行的一个具体程序),这三者都有着必然的联系。

    首先说说什么是程序程序是存放在磁盘文件中的可执行目标文件(Windows下是exe文件),想一想是不是?你用IDE新建一个工程,要么是在桌面创建,要么是在D、E、F盘创建,总之它们都是磁盘区域。一个程序本身有生命吗?没有,只有处理器赋予了它生命力时,即你在电脑上(即操作系统)运行它的时候,他才能成为一个活动的实体,我们称这个活动实体为进程,也就是说,进程是一个“执行中的程序”,它是在操作系统上运行的一个程序实体。

    然后再说说什么是线程首先,一个线程是运行在一个进程(即一个程序实体)下面的;其次,一个进程实体下可以有多个线程,线程的本质也是一个函数,只是这个函数可以和进程同步执行;接着,其实进程也是一个线程,这里有两个概念:主线程对等线程每个进程开始生命周期是都是一个单一的线程,它就是主线程,在某一时刻,主线程可以创建一个新的线程,这个线程就是对等线程,对等线程可以有多个(对等线程下面又可以新建它自己的对等线程,这时对等线程就成了主线程);最后主线程和对等线程的唯一区别仅仅在于主线程是该进程中第一个开始运行的线程,对等线程创建并启动后就和主线程在同步的运行,如果没有加入线程控制操作,你无法预测主线程和对等线程的具体执行顺序,记住,同步运行和开始运行是两个不同的概念。

    为了形象的理解线程和进程,博友可以链接这一篇博文,图文并茂,很好理解进程与线程的一个简单解释(非常值得链接进去看一看)。


三、进程间切换

   前面已经说过,进程是一个“执行中的程序实体” ,如浏览器是一个进程,QQ也是一个进程,但是你在一台电脑上“同时”运行这个两个进程,即一边聊天,一般浏览网页,完全满足了你的多元化需求啊。但这个“同时”只是看起来的“同时”,因为你在某一时刻还是只能进行聊天或者浏览网页。如果你的电脑配置不是很高,但你同时打开了很多个进程,如QQ、浏览器、视频播放器、音乐播放器、单机游戏、VS2010、QT Creator等,刚刚也讲过,你在同一时刻也只是在某一具体进程上操作,这是其他进程都在睡觉,等待你去操作它们,可能在你只连续操作一个进程的时候(如使用VS2010编辑程序),你不会觉得电脑卡顿,但是突然你接收到你个好朋友的QQ消息,这时你肯定要去点击QQ去查看这个消息,这个时候你的配置不高的电脑就会出现卡顿的现象,可能你点击之后过了半分钟QQ才响应过来(你我想肯定有过,我反正经常有)。

    再总结一下现象:当你打开多个进程(这就是进程并发),如果某一段时间你只操作一个单独的进程,你不会觉得电脑卡,但是当你从你正在工作的进程切换到另一个进程时(如从VS2010切换到QQ),电脑就会出现卡顿的现象,半天反应不过来。这是为什么呢?这是由于不同进程间的切换需要一定的时间消耗造成的。

    既然进程间可以进行切换,也就是说一个进程是间断执行的,进程的间断性,决定了进程具有多种不同的状态,即实质上进程是在这几种不同的状态间进行切换。进程主要有三种状态:就绪状态、运行状态、阻塞状态。

        (1)就绪状态

            当一个进程获得了除处理机以外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。

        (2)运行状态

            当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。

        (3)阻塞状态

            这里详细说一下进程阻塞状态,进程阻塞就是说这个进程现在暂停了,它或者是在等待某种条件或事件的发生,在条件满足或事件到达之前这进程无法继续执行。进入阻塞状态的进程会暂时放弃CPU资源,处于暂停状态(可以理解为睡眠、等待)。最简单的进程阻塞例子就是,如果你写一个打印字符“A”的程序,程序很简单,如下:

#include <iostream>#include <string>using namespace std;void main(){    char a;    cout << "请从键盘输入字符A: ";    cin >> a;     //从键盘输入HelloWOrd    cout << a << endl;}
你可以试着编辑运行这个程序,出现下面这个界面,提示你输入字符A:


这时,如果你一直不从键盘输入字符“A”,这个程序(进程)就一直停滞在这里,也就是说该进程进入了阻塞状态,但这个进程的阻塞状态不会影响它自己,也不会影响其他的进程,比如你可以接下来去打开QQ进行聊天程序,直到你想起来你的这个打印字符的程序还没有完成,你应该去完成它,然后你用鼠标选中控制台,从键盘输入字符“A”,这个程序就继续运行,打印字符“A”,然后程序运行完毕,进程结束。


    在上面这个例子中,就包含了上述进程的三个状态。具体为,程序编辑完成之后,你点击运行按钮,运行该程序,这个程序就经历了就绪状态和运行状态,这两个状态在这个例子中是连续完成的,只是我们感觉不到,运行之后,然后程序在控制台打印“请从键盘输入字符A:”提示你输入字符,到这里这个进程就进入阻塞状态,然后你去干其他事情(QQ聊天),这个进程就继续阻塞(其实这也是一种就绪状态),接着你在控制台中输入字符“A”,这进程就结束阻塞状态,切换到运行状态,完成整个进程的工作,打印字符“A”。

    最后,简单说说为什么进程间切换会出现电脑卡顿的现象,因为各个进程具有独立的运行环境(即与这个进程运行相关的各种资源),进程间切换的动作需要保存当前进程的信息,恢复下一个运行进程的信息,然后把系统使用权转交给新的运行进程,这个过程是需要一定的时间的,所以会出现电脑卡顿现象。


四、线程状态

    进程具有不同的状态,同样线程也具有不同的状态,总的来说,线程从创建、运行到结束总是处于以下五个状态中,并在其中不停的切换,具体五中状态为:新建状态、就绪状态、运行状态、阻塞状态及死亡状态,各个状态的理解与进程状态类似。

    这里还是详细说一下线程的阻塞状态,本质上来讲,线程的阻塞状态还是和进程的阻塞状态一样理解, 在线程运行过程中,可能由于各种原因进入阻塞状态:
        1>线程通过调用sleep方法进入睡眠状态;
        2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
        3>线程试图得到一个锁,而该锁正被其他线程持有;
        4>线程在等待某个触发条件;
        ......           

    也就是说一个线程进入阻塞状态,也是指这个线程本身暂停了,但它还没有结束运行,只是暂时让出CPU资源,这时其他处于就绪状态的线程就可以获得CPU资源,进入运行状态,即一个线程进入阻塞状态不影响其他的对等线程执行。

    线程由于它本身是在一个进程中运行,所以线程间切换比进程间切换需要保存和恢复的信息要少很多,所以线程间切换要比进程间切换快很多。



1 0
原创粉丝点击