云计算百科
云计算领域专业知识百科平台

【linux应用软件编程】多任务学习2【线程】

文章目录

  • 线程
    • 一、线程的相关定义
    • 二、线程的创建
    • 三、进程和线程的区别
    • 四、线程的调度
    • 五、线程的消亡
    • 六、线程相关的函数接口
      • 6.1 创建线程
      • 6.2 线程的非分离属性:
      • 6.3 线程退出及资源回收
    • 七、线程的同步和互斥
      • 7.1 线程间通信
      • 7.2 线程间互斥机制
      • 7.3 线程间同步机制
    • 八、死锁

请添加图片描述

线程

一、线程的相关定义

  • 线程是一个轻量级的进程,用来实现多任务并发。
  • 线程是操作系统任务调度的最小单位。
  • 进程是操作系统资源分配的最小单位。

主线程:创建线程的进程。 次线程:由进程创建出来的线程。

二、线程的创建

  • 线程由所在的进程创建,线程一定是属于某个进程的。
  • 线程创建时,所在进程为其分配独立的栈区空间(默认8M),线程共用进程的堆区、数据区、文本区、内核区。 在这里插入图片描述

三、进程和线程的区别

进程线程
概念 操作系统资源分配的最小单位 CPU任务调度的最小单位
效率 进程要为进程分配4G的虚拟内存空间 线程的创建要比进程创建要块,只需要分配栈区空间即可
内存 消耗大(4G) 消耗小(仅需独立的8M栈区空间,其余的与进程共享)
并发量 相同资源环境下,并发量少 并发量多
安全性 进程间空间独立,安全性高 除栈区外,其余空间共用,安全性低
通信 进程间不能直接通信,需要使用IPC机制通信 线程可以直接通信(例如:全局变量、全局队列等)

四、线程的调度

宏观并行、微观串行 调度方式与进程相同

五、线程的消亡

  • 线程退出
  • 回收线程的资源空间 具体函数接口在后面讲解。
  • 六、线程相关的函数接口

    6.1 创建线程

    pthread_create

    • 函数原型:#include <pthread.h>

      int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

    • 功能

      创建并启动一个线程。

    • 参数

      thread:保存线程ID的变量地址; attr:设置线程属性的变量地址;(NULL:按照默认属性创建) start_routine:函数指针,指向线程执行的任务函数的指针(线程任务函数); arg:传递给线程任务函数的参数。

    • 返回值:

      成功:返回0; 失败:返回错误码(!0)。

    • 获取ID号:

      pthread_self() //获取当前线程ID号

    注意:

  • 使用线程相关接口时,需要编译和链接线程库:-pthread/-lpthread;
  • 创建线程的主线程不能先于此线程结束,
  • 6.2 线程的非分离属性:

    线程的分离属性:不需要被其他线程回收的线程,称之为具有分离属性的线程,将来执行结束,由操作系统回收。

    设置tid对应的线程为分离属性的线程。 pthread_detach(tid); 使用场景:其他线程没有机会回收该线程时,可以将该线程设置成分离属性。

    线程的非分离属性:可以被其他线程结束和回收的线程,称为具有非分离属性的线程。 因此,具有非分离属性的线程结束后,必须要被其他线程回收。

    线程默认属性:非分离属性

    6.3 线程退出及资源回收

  • 线程执行结束,return;
  • 线程所在进程结束;
  • pthread_exit退出线程。
  • pthread_exit

    • 函数原型#include <pthread.h>

      void pthread_exit(void *retval);

    pthread_join

    • 函数原型

      #include <pthread.h>

      int pthread_join(pthread_t thread, void **retval);

    • 功能

      阻塞回收线程资源空间和状态。

    • 参数

      thread:要回收的线程的线程ID。 retval:保存线程退出状态变量的地址; NULL表示不接受状态。

    • 返回值:

      成功:返回0; 失败:返回!0。

    七、线程的同步和互斥

    7.1 线程间通信

    位于数据区的全局变量、堆区申请的空间(队列)、pthread_create传参、条件变量。

    多线程访问临界资源时,存在资源竞争问题。

    • 临界资源:多个线程可以同时访问的区域(文件、数据库、内存中的全局变量等)。
    • 资源竞争:多个线程同时想对一块内存进行访问。
    • 临界区:访问临界资源的这段代码称为临界区。
    • 解决方法:互斥机制。

    7.2 线程间互斥机制

    互斥机制:让多个线程访问临界资源时,具有排他性访问特性。 互斥机制的实现:互斥锁。 1. 创建一个互斥锁对象:pthread_mutex_t 2. 初始化互斥锁:pthread_mutex_init(); 3. 加锁:pthread_mutex_lock(); 4. 解锁:pthread_mutex_unlock(); 5. 销毁互斥锁:pthread_mutex_destroy()

    在linux系统终端中安装互斥锁的库指令: sudo apt-get install manpages-posix manpages-posix-dev

    • pthread_mutex_init/pthread_mutex_destroy

      • 函数原型:#include <pthread.h>

        int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
        int pthread_mutex_destroy(pthread_mutex_t *mutex);

      • 功能:

        初始化/销毁一个锁。

      • 参数:

        mutex:要初始化/销毁的锁对象的地址; attr:锁属性的首地址(NULL:默认属性)。

      • 返回值

        成功:返回0; 失败:indicate the error.

    • pthread_mutex_lock/pthread_mutex_unlock

      • 函数原型:#include <pthread.h>
        int pthread_mutex_lock(pthread_mutex_t *mutex);
        int pthread_mutex_unlock(pthread_mutex_t *mutex);
      • 功能:

        上锁/解锁。

      • 参数:

        mutex:锁地址。

    其他锁: 读写锁:读共享,写独占。 自旋锁:申请不到锁时,一直占用CPU。

    7.3 线程间同步机制

    线程间同步:让多个线程执行任务时,具有一定先后顺序。 在这里插入图片描述

    信号量:资源数; 1. 创建信号量对象sem_t; 2. 初始化信号量sen_init(); 3. 申请信号量(P操作)sem_wait(); 4. 释放信号量(V操作)sem_post(); 5. 销毁信号量;sem_destroy()

    • sem_init
      • 函数原型:#include <semaphore.h>
        int sem_init(sem_t *sem, int pshared, unsigned int value);
      • 功能:

        初始化一个信号量。

      • 参数:

        sem:信号量对象地址; pshared:0:线程间共享使用;!0:进程间共享使用; value:信号量初始值。

      • 返回值:

        成功:返回0; 失败:返回!0。

    • sem_wait
      • 函数原型:#include <semaphore.h>
        int sem_wait(sem_t *sem);
      • 功能:

        申请一个信号量。

      • 参数:

        sem:信号量对象地址。

      • 返回值:

        成功:返回0; 失败:返回!0。

    • sem_post
      • 函数原型:#include <semaphore.h>
        int sem_post(sem_t *sem);
      • 功能:

        释放一个信号量。

      • 参数:

        sem:信号量对象地址。

      • 返回值:

        成功:返回0; 失败:返回!0。

    八、死锁

    死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,且互相请求对方未释放资源,从而导致陷入永久等待状态的情况。

    • 现象

      • 现象1:忘记释放锁
      • 现象2:重复加锁
      • 现象3:多线程多锁,抢占锁资源不当

      如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁

    • 产生死锁的四个必要条件

    • 互斥条件:一个资源同一时刻只能被一个任务占用(一个执行流获取锁后,其它执行流不能再获取该锁)。
    • 请求与保持条件:已经拿着一部分资源不释放,同时又去申请新的资源(执行流本身使用着一把锁并不释放,还在请求别的锁)。
    • 不剥夺条件:资源只能由持有者主动释放,系统/其他任务不能强行抢过来(A执行流拿着锁,其它执行流不能释放)。
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)。
    • 四条全中 = 死锁,破掉任意一条 = 解除

    • 解决方法

    • 锁一定要成对出现
    • 使线程的加解锁顺序一致
    • 破坏环路等待条件

    使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的资源

    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    int sem_trywait(sem_t *sem);

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【linux应用软件编程】多任务学习2【线程】
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!