当前位置:C++技术网 > 资讯 > 编程中线程的通俗深入理解

编程中线程的通俗深入理解

更新时间:2015-06-23 16:13:01浏览次数:1+次

    在使用线程前,我们必须了解线程相关的基础知识。线程与进程不一样,线程依托于进程,是一个执行个体。而进程则有更多的资源,比如变量,缓冲等。线程不会独立于进程而存在的。每个进程可以创建很多线程,并且至少要有一个线程,否则操作系统则认为无线程的进程是多余的,没有意义的,所以会清除进程。而第一个线程就是这个进程的主线程。而我们经常写的控制台程序,是单线程程序,这个线程就是主线程。
    在编程中来看,每一个过程或者动作,基本以函数的形式来包装。就好像每一个对象成员函数都完成一个功能一样。线程也是完成特定功能的,所以也是以函数的形式包装起来。只不过,这个函数有一个单独的线程来执行,而一般的成员函数是由主线程来执行,所以,在主线程中执行循环等待,那么主线程其他的动作都得等循环执行完才能执行,因为是同一个线程,必须按顺序。如果是大量的循环,基本就卡住了。所以,创建的新线程就可以将这个循环里的操作接手过去,在后台执行,前台让主线程来执行,那么此时,一般就不会出现卡住的情况。
    而线程对应的函数称为线程函数,可以粗略理解为对象成员函数那样的一个函数而已,没有那么恐怖。因为很多不熟悉的同学,包括我以前,听到回调函数,线程函数等等,心里都发虚,什么回调,什么参数等等,因为不熟悉,就不能简化,从而感觉云里雾里。所以,先放松神经,看完自然也懂了,不过看完一定要练习一下,不然提到这个以后可能时间长了还是会发虚的。
    线程函数和普通函数一样,要返回值,要参数,要函数名。但是线程函数还是与普通的函数有一些特别之处,下面就稍作讲解。
    既然是线程函数,也就是与线程相关。也就是,这个函数只给这类线程执行的,而不会给主线程执行。简单比喻一下,线程相当于一个职员,线程函数相当于一个任务,主线程是领导。主线程要线程去执行这个任务,那线程就一直做这个任务直到完成,如果没有其他任务,那线程就死亡了。第二次,有一个新线程创建了,主线程又叫它去执行这个任务,它也是将这个任务执行完才结束。也就是说,一个线程函数,可以被很多线程执行,就像一个任务被多个职员执行一样,不过,这些线程都是被创建指派过来的,而不是线程自己说来就来说走就走的。而线程其实只是一个劳动力而已,什么都可以做,就看要他做什么,线程函数只是其中一种任务而已。所以,可以有很多的线程函数,每一种函数代表一种任务,也可以有很多线程,每一个线程都可以执行任何任务。只不过可悲的是,命运往往是注定的一样,线程创建时就注定了命运。也就是说,创建线程时就需要指定一个线程函数,相当于给它指定了任务,且这个线程就一直会执行这个任务。这是站在线程的角度来看的,所以线程与任务是绑定了的。要想线程寿命和主线程一样长,那就用死循环吧。站在人的角度来看,我们创建的所有线程都是一样的,只不过我们在写代码的那一瞬间就指定了一个任务给一个线程,或许机缘巧合,在写代码时写成了另外一个线程函数,这样就改变了它的命运一样。
    我想,这样的解说,读者应该可以有一个比较深刻的感性认识吧。其实,在写代码时就是这样的。先不说具体的语法,就这样理解到了线程,使用就不难了。上面线程与线程函数的关系(劳动者与任务的关系)就说清楚了。
    下面说说线程函数。线程的本身就没什么再说的了,就是执行线程函数里的代码就行了,关键就在于线程函数了。我们来看看线程函数的形态美。如果线程函数奇丑无比的话,或许线程一见到线程函数时可能就选择自杀了吧。所以既然有那么多线程拼命的追求线程函数,想必线程函数还是具有很大的美感的,这就是线程函数的魅力吧。
    线程函数,表面上看,确实与普通的函数一样。因为参数、函数名,返回值基本一样的规则。不过,线程函数与操作系统有血缘关系,所以,我们要将操作系统联系起来。
    在Windows中,线程之间是不可以跨界的,都是在自己的虚拟地址空间中执行,互不干扰。而一个类对象,是类实例化的东西,是动态创建,被分配到一个线程中,多数情况下是主线程。而对象是动态创建,那么对象的成员函数也就是动态从类中连接函数到类对象的。对象共享类成员函数,只需要在对象中提供一个类函数的地址即可。不过像对象成员函数一般与成员变量有关联,而成员对象是动态分配的一个内存块,所以,要事先写定成员函数,必然会出大问题,因为如果你的函数先执行,对象后创建,那么执行对象成员函数就失败了。这是对象动态分配的根本原因,因为动态分配的是成员变量,动态指定成员函数连接到类函数的入口地址。而线程,是一个执行体,与类,与对象等都没有任何关系,只爱慕它的线程函数,只知道它的任务。即使没有类,没有对象,没有变量,只要有正确的线程函数入口地址,就可以找到任务,线程就可以成功创建。而线程的创建,可以很早,在其他对象都没有创建时,就可以被创建出来。一旦创建出来,就要找到它的线程函数。所以,线程函数的地址必须非常非常早就出生,而不是平常说的“我的媳妇还在岳母肚子呢”,如果是这样,线程就无法活下去了。对象的成员函数就不用考虑了,因为就算类存在了,还可能没有实例化,那就不存在这个函数。线程就找不到。所以说,那就只有全局函数和类静态函数了。程序启动后,全局函数就可以用了。当然类静态函数也有类似的功效,也是相当于全局函数。因为类就是一个说明,只要程序启动,类的静态的东西,都已经载入内存了,自然也是可以使用了。所以不要觉得类静态函数作为线程函数很奇怪,问题就在于也可以提供一个特性,那就是,比用户创建的线程先出来,先存着,拥有让新生线程找到归宿的能力。如果理解到这里,我想对于线程的使用,应该不难了吧。
    而类静态函数的定义,这个自然简单了。参数传递,对于一些特殊的条件创建的线程,操作系统可能规定了形式,这个按照说明也很清楚。
    还有一个就是回调函数的问题。有的线程函数是有的不是。回调就是让系统来调用的。如果是自己写一个执行任务的线程,与操作系统无关,这个线程就不与操作系统直接打交道,那么就不用是回调函数了,而操作系统规定的都是需要让系统来调用的,自然要规定一个形式,保持一致,才能正确调用。而普通执行的线程,一般都不用交互,所以就不用纠结回调问题。如果有不清楚或者疑问,欢迎一定要提出来讨论。