Linux多线程编程

Linux多线程编程

1-1、为什么要使用多线程

要做2件事,一件需要阻塞等待,另一件需要实时进行。
①例如播放器:一边在屏幕上播放视频,一边在等待用户的按键操作。
如果使用单线程的话,程序必须一会查询有无按键,一会播放视频。
查询按键太久,就会导致视频播放卡顿;视频播放太久,就无法及时响应用户的操作。
并且查询按键和播放视频的代码混杂在一起,代码丑陋。
如果使用多线程,线程1单独处理按键,线程2单独处理播放,可以完美解决上述问题。

②实际项目中例如汽车仪表的车速,车速的输入既有Pulse输入,也有CAN信号输入,二者只能取其一。正常情况下,CAN输入的优先级更高。那么就将CAN信号的输入处理作为一个线程,Pulse的输入处理作为第二个线程,通过一个全局变量去裁决,当前是使用CAN信号输入还是使用Pulse输入,如果是使用CAN信号输入,那么Pulse输入所在的线程就会进入休眠,如果CAN信号途绝,唤醒Pulse输入所在的线程,转而使用Pulse输入。

1-2、线程的概念
所谓线程,就是操作系统所能调度的最小单位。普通的进程,只有一个线程在执行对应的逻辑。我们可以通过多线程编程,使一个进程可以去执行多个不同的任务。相比多进程编程而言,线程具有共享资源,比如全局变量,每个线程都可以去访问它,与进程共享内存空间,是的系统资源消耗减少。

1-3、线程的标识 pthread_t
对于进程而言,每个进程都有一个唯一对应的PID号来标识该进程,而对于线程而言,也有一个类似的“PID号”,名为tid,其本质是一个pthread_t类型的变量。
线程号(PID)与进程号(tid)是表示线程和进程的唯一标识,但是对于线程号而言,仅仅在其所在的进程上下文中才有意义。

获取线程号
pthread_t tid = pthread_self(); //获取主线程的tid号
在这里插入图片描述
1-4、线程的创建
pthread_create函数
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

向线程传入参数
1、可以有值传递和址传递两种形式 。原因是void *可以强转为任何类型
2、需要传递多个参数时通过结构体
在这里插入图片描述

1-5、线程的退出与回收

线程的退出情况有三种:
①进程结束,进程中所有的线程也会随之结束
②通过函数pthread_exit来主动的退出线程。
③被其他线程调用pthread_cancel来被动退出。

当线程结束后,主线程可以通过函数pthread_join/pthread_tryjoin_np来回收线程的资源,并且获得线程结束后需要返回的数据。

①线程资源回收(阻塞方式)
pthread_join函数直到成功回收线程后才返回。

②线程资源回收(非阻塞方式)
pthread_tryjoin_np为非阻塞模式回收函数,通过返回值判断是否回收掉线程,成功回收则返回0

2-1、线程的控制-多线程编程临界资源访问
当线程在运行过程中,去操作公共资源,如全局变量的时候,可能会发生彼此“矛盾”现象。例如线程1企图想让变量自增,而线程2企图想要变量自减,两个线程存在互相竞争的关系导致变量永远处于一个“平衡状态”,两个线程互相竞争,线程1得到执行权后将变量自加,当线程2得到执行权后将变量自减,变量似乎永远在某个范围内浮动,无法到达期望数值。

为了解决上述对临界资源的竞争问题,pthread线程引出了互斥锁来解决临界资源访问。
通过对临界资源加锁来保护资源只被单个线程操作,待操作结束后解锁,其余线程才可获得操作权。

2-2、互斥锁API简述
多个线程都要访问某个临界资源,比如某个全局变量时,需要互斥地访问:我访问时,你不能访问。

①初始化互斥量
int pthread_mutex_init(phtread_mutex_t *mutex, const pthread_mutexattr_t *restrict attr);

该函数初始化一个互斥量,第一个参数是改互斥量指针,第二个参数为控制互斥量的属性,一般为NULL。当函数成功后会返回0,代表初始化互斥量成功。

②加锁(阻塞方式)
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
成功:返回0

一旦加锁成功后,其余线程遇到lock函数时候会发生阻塞,直至获取资源的线程执行unlock函数后。unlock函数会唤醒其他正在等待互斥量的线程。

加锁(非阻塞方式)
int pthread_mutex_trylock(pthread_mutex_t *mutex);
该函数同样也是一个线程加锁函数,但该函数是非阻塞模式通过返回值来判断是否加锁成功,用法与上述阻塞加锁函数一致。

int pthread_mutex_destory(pthread_mutex_t *mutex);
成功:返回0

特别注意的是,当获取lock之后,必须在逻辑处理结束后执行unlock,否则会发生死锁现象!导致其余线程一直处于阻塞状态,无法执行下去。在使用互斥量的时候,尤其要注意使用pthread_cancel函数,防止发生死锁现象!

通过加入互斥量,保证了临界变量某一时刻只被某一线程控制,实现了临界资源的控制。

2、多线程编执行顺序控制
上述添加互斥锁的方法解决了临界资源的访问,但是对线程的执行顺序无法得到控制,因线程都是无序执行,之前采用sleep强行延时的方法勉强可以控制执行顺序,但此方法在实际项目情况往往是不可取的。
其仅仅可解决线程创建的顺序,当创建之后执行的顺序又不会受到控制,于是便引入了信号量的概念,解决线程执行顺序。

2-1、信号量API简述

信号量跟互斥量不一样,互斥量用来防止多个线程同时访问某个临界资源。信号量起通知作用,线程A在等待某件事,线程B完成了这件事后就可以给线程A发信号。

①初始化信号量
int sem_init(sem_t *sem,int pshared,unsigned int value);

该函数可以初始化一个信号量,第一个参数传入sem_t类型指针;
第二个参数传入0代表线程控制,否则为进程控制;
第三个参数表示信号量的初始值,0代表阻塞,1代表运行。
待初始化结束信号量后,若执行成功会返回0。

②信号量P/V操作
int sem_wait(sem_t *sem);(阻塞方式)
int sem_post(sem_t *sem);

sem_wait函数作用为检测指定信号量是否有资源可用,若无资源可用会阻塞等待,若有资源可用会自动的执行“sem-1”的操作。
所谓的“sem-1”是与上述初始化函数中第三个参数值一致,成功执行会返回0。

sem_post函数会释放指定信号量的资源,执行“sem+1”操作。

int sem_trywait(sem_t *sem);(非阻塞方式)
此函数是信号量申请资源的非阻塞函数,功能与sem_wait一致,唯一区别在于此函数为非阻塞。

③信号量销毁
int sem_destory(sem_t *sem);
该函数为信号量销毁函数,执行过后可将信号量进行销毁。
成功:返回0

3-1、线程使用流程图

有关多线程的创建流程下图所示,首先需要创建线程,一旦线程创建完成后,线程与线程之间会发生竞争执行,抢占时间片来执行线程逻辑。
在创建线程时候,可以通过创建线程的第四个参数传入参数,在线程退出时亦可传出参数被线程回收函数所回收,获取到传出的参数。
在这里插入图片描述
3-2、互斥量使用流程图
在这里插入图片描述
3-3、信号量使用流程图
当多个线程出现后,同时会遇到无序执行的问题。有时候需要对线程的执行顺序做出限定,变引入了信号量,通过PV操作来控制线程的执行顺序,如下图所示。

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux 多线程编程是一种技术,可以让一个程序并行地处理多个任务。它可以提高程序的执行效率,更有效地使用计算机的资源,并减少系统响应时间。Linux 是一种流行的操作系统,支持多线程编程多线程编程是指在同一进程中同时执行多个线程,每个线程执行自己的任务。下面是一些关于 Linux 多线程编程的基本概念和技术: 1. 线程和进程的区别:线程是进程内的一个执行单元,进程是操作系统分配资源的一个独立单位。 2. 线程同步:线程同步是指协调多个线程之间的执行顺序,防止出现数据竞争和死锁等问题。常见的线程同步技术包括互斥量、条件变量和信号量等。 3. 线程池:线程池是一种预先创建一组线程并重复使用的技术。线程池可以提高多线程程序的效率和性能。 4. POSIX 线程库:POSIX 线程库是 Linux 操作系统支持的一种多线程编程接口,提供了一套标准的多线程 API,包括创建、销毁、同步和调度线程等功能。 5. 多线程调试:多线程程序的调试需要注意避免数据竞争和死锁等问题,可以使用调试工具和技术,如 gdb 和 Valgrind 等。 总之,多线程编程Linux 程序员必备的技能之一,掌握多线程编程技术可以提高程序的效率和性能,同时也需要注意避免常见的线程问题。 ### 回答2: Linux 多线程编程是一种在 Linux 操作系统上开发并行应用程序的方式,它允许一个程序同时执行多个线程,从而提高程序的响应速度和运行效率。在 Linux 中,线程是轻量级的进程,它们共享同一进程的资源和数据,可以同时运行在不同的 CPU 核心上,使得程序在多核系统中具有更好的性能表现。 Linux 提供了多种多线程编程的 API,其中最常用的是 pthreads 库,它是一组 C 语言函数,可用于创建、同步和管理多个线程。使用 pthreads 库编写多线程程序的基本步骤包括定义线程函数、创建线程、执行线程、同步线程和销毁线程,这些步骤需要程序员显式地调用相关的 API 函数来实现。 在编写多线程程序时,必须考虑线程之间的共享资源和同步问题。共享资源包括程序的数据、文件、网络连接等,可以使用临界区、互斥锁、信号量等技术来保护。同步问题则是确保多个线程之间按照正确的顺序执行,不会产生死锁、饥饿等问题,可以使用信号量、互斥锁、条件变量等技术来实现。 此外,多线程编程还需要考虑到线程的调度问题,即如何让不同的线程在不同的时间片内执行,从而实现线程的抢占和优先级控制。Linux 提供了优先级调度器和时间片分配器来实现线程的调度,程序员可以根据需要设定优先级和时间片长度来控制线程的执行顺序和时间切片。 总之,Linux 多线程编程是一种高效、灵活和可扩展的编程模型,能够充分利用多核系统的性能,并实现程序的并行化和异步化。开发者需要熟悉多线程编程的基本概念、API 和技术,遵循正确的资源共享和同步策略,才能编写出高质量、可靠、并发的多线程程序。 ### 回答3: Linux 多线程编程是指在 Linux 操作系统下使用多个线程同时运行程序来提高程序的运行效率、并实现多任务处理。多线程编程具有使用方便、管理灵活、响应速度相对于进程更快的优势,常被应用于高并发服务器中。 在 Linux 中,多线程编程的实现主要依赖于 pthread 库。该库提供了一些线程函数和数据结构,用于创建、控制、同步和分离线程等操作。以下是一些常用的 pthread 函数: 1. pthread_create():用于创建一个新线程; 2. pthread_join():主线程阻塞等待子线程结束; 3. pthread_exit():用于在线程代码中退出线程; 4. pthread_mutex_lock():线程加锁; 5. pthread_mutex_unlock():线程解锁; 6. pthread_cond_wait():线程等待; 7. pthread_cond_signal():唤醒等待的线程。 除了 pthread 库,Linux 还提供了其它一些可用于多线程编程的工具和技术,如: 1. OpenMP:一种基于共享内存的多线程编程模型; 2. MPI:一种消息传递的分布式并行编程模型。 当进行多线程编程时,需要注意以下几个方面: 1. 多线程编程的并发性可能会导致一些竞态条件,需要使用锁或互斥量进行同步; 2. 在实现多线程编程过程中,应该尽量避免使用全局变量或静态变量; 3. 在多线程编程实践中,应注意资源的释放和内存泄漏的问题。 总之,Linux 多线程编程是一项非常重要的技能,它能够在提高程序性能和响应速度方面发挥重要作用。熟练掌握多线程编程技术,对于编写高效稳定的服务端程序和优化多线程应用程序的性能都非常有益。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值