当前位置 博文首页 > Scissors_初夏的博客:初夏小谈:全面剖析多线程(一)

    Scissors_初夏的博客:初夏小谈:全面剖析多线程(一)

    作者:[db:作者] 时间:2021-08-28 10:00

    一、多线程是什么?

    1.在说起多线程前,要先来说说进程,那么进程又是什么呢?

    进程进程顾名思义,就是运行中的程序,这个说法不够精确。在操作系统中,一旦一个程序被运行起来,它就会被加载到内存中,操作系统就会为它创建一个进程控制块来将这个程序描述起来。至此以后运行的信息都会被进程控制块记录起来(PCB),因此进程控制块就是进程就是PCB,在Linux下进程可以看作是task_struct结构体。

    2.说完进程,那么线程是什么?二者又有什么关系?

    在Linux下线程是用PCB来模拟的,因此Linux下的线程就是轻量级进程。Linux下没有真正的线程。那么如果说此时线程变成了轻量级进程,那么进程又是什么?这时进程就变成了线程组,进程里面不仅包含了每个线程的各自信息还有它们的共享信息。一个进程中至少包含了一个或多个线程。

    只有在程序运行时会给进程分配资源,所以进程或者线程组是资源分配的基本单位。而线程中操作系统不会为它单独分配自己所需要的所有资源。而是在为进程分配的资源中来划分一块区域为己独有,并且此进程下的所有线程共用一个虚拟地址空间,因此共享进程的代码段和数据段。Linux下pcb成为了线程所有线程是cpu调度的基本单位。

    3.那么多线程共享哪些数据,又有哪些独特的数据呢?

    1.共享的数据有:

    1.文件描述符。2.每种信号的处理方式(SIG_IGN, SIG_DFL或者自定义的信号处理函数)。3.当前工作目录。4.用户ID和组ID。

    2.独有数据:

    虽然共享了这么多数据,但是每个线程有自己的pcb,因此线程可以同时运行,并且不会造成调用栈混乱。

    1.栈。2.寄存器(文件描述符)。3.信号屏蔽字。4.errno错误信息。5.线程标识符。

    4.多线程的优缺点:

    主要从两方面来分析:IO密集和CPU密集来说

    优点:由于多个线程共享虚拟地址空间所以:

    ? ? ? ? (1)线程间通信简单

    ? ? ? ? (2)线程的创建/销毁成本更低

    ? ? ? ? (3)线程的调度成本更低

    ? ? ? ? (4)线程的执行粒度更细

    缺点:

    ? ? ? ? (1)线程缺乏访问控制----exit退出将是整个进程

    ? ? ? ? (2)健壮性较低---线程的某些错误会导致整个进程的退出或者失败。

    二、来说说多线程的控制

    由于Linux下没有真正的线程,所以在操作系统中没有提供直接创建线程的系统调用接口。这将使得我们实现一个线程的创建将变得异常艰难。所以对此那些巨佬就不服气了,他们实现了一套线程控制接口---封装了线程库来给我们使用。所以在此创建的线程是用户态的线程,在调用时,内核中对应有轻量级进程实现程序的调度运行。

    线程创建---》线程终止---》线程等待---》线程分离---》线程安全。

    1.线程创建:pthread_create

    在这个函数中的参数thread是用来保存返回的线程ID,attr是线程属性,一般置NULL,star_routine是线程入口函数,arg是给线程传递的参数。

    代码实现:

    运行结果:

    在代码中tid就是创建的线程地址空间的首地址。

    在这里PID就是线程组ID也就是进程PID。进程的PID就是程序运行起来第一个被CPU执行的线程的PID。LWP是每个线程自己的PID。

    2.线程终止:

    在main中renturn将退出进程,而在函数中即线程入口函数中return就是退出线程。

    退出调用线程函数:pthread_exit 退出调用线程,pthread_cancel 取消指定线程。

    代码实现线程终止:

    运行结果:

    子进程被终止。那么自己可不可以取消自己呢?

    在下面我取消主线程运行显示:

    虽然这样可以看出主线程被终止,但这属于非法操作,但是出现了僵尸线程。这就引出来下一个线程问题:

    3.线程等待:线程退出也会形成僵尸线程

    线程在创建出来以后,默认带有一个属性即joinable属性,当线程处于这个属性时,线程必须被等待退出,才能将资源释放。否则它不会自动回收资源从而造成资源泄露。

    pthread_join函数

    代码显示:

    运行结果:

    此时就不会产生僵尸线程,因为接受线程的退出返回值。资源被释放。

    4.线程分离:

    既然有时我们没有必要接受线程的退出返回值。就需要分离线程。分离线程只需将它的joinable属性修改为datach属性,处于这个属性的线程,退出后将自动回收资源。并且这个属性的线程不能被等待,否则报错。

    pthread_detach(tid):

    thread:线程的pid

    代码实现:

    运行结果:

    此时创建的线程已经被分离,pthread_join将获取不到线程的退出返回值所以乱码。

    线程分离可以在任何线程时间分离,包括分离自己。

    5.线程安全:

    由于多个执行流之间对数据的竞争操作--不安全操作,有可能造成数据的异常。

    如何实现线程的安全:同步与互斥

    同步:对临界资源访问的时序可控性

    互斥:对临界资源同一时间的唯一访问性(原子操作)

    互斥锁:

    代码实现:

    运行显示:

    5.2条件变量:

    用于实现线程间的同步---唤醒与等待

    代码实现:

    运行结果:

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 珍&源码

    cs
    下一篇:没有了