嵌入式学习Day30
线程控制中互斥与同步:
概念:
互斥 ===》在多线程中对临界资源的排他性访问。
互斥机制 ===》互斥锁 ===》保证临界资源的访问控制。
Linux中的互斥锁
互斥锁(Mutex)是Linux中用于线程同步的基本机制,确保同一时间只有一个线程能访问共享资源。以下是Linux中互斥锁的使用方法和关键概念。
框架:
定义互斥锁 ==》初始化锁 ==》加锁 ==》解锁 ==》销毁
互斥锁的初始化
在Linux中,互斥锁通过pthread_mutex_t
类型表示。初始化方式分为静态初始化和动态初始化。
- 静态初始化:直接使用宏
PTHREAD_MUTEX_INITIALIZER
。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- 动态初始化:通过
pthread_mutex_init
函数完成。
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
互斥锁的加锁与解锁
- 加锁:使用
pthread_mutex_lock
函数,如果锁已被占用,线程会阻塞。用指定的互斥锁开始加锁代码,加锁后的代码到解锁部分的代码属于原子操作,在加锁期间其他进程/线程都不能操作该部分代码, 如果该函数在执行的时候,mutex已经被其他部分使用则代码阻塞。
pthread_mutex_lock(&mutex);
// 临界区代码
- 非阻塞加锁:使用
pthread_mutex_trylock
,如果锁不可用,函数立即返回错误。
if (pthread_mutex_trylock(&mutex) == 0) {// 临界区代码
}
- 解锁:使用
pthread_mutex_unlock
函数。将指定的互斥锁解锁。
解锁之后代码不再排他访问,一般加锁解锁同时出现。
pthread_mutex_unlock(&mutex);
互斥锁的销毁
使用pthread_mutex_destroy
函数释放互斥锁资源。
pthread_mutex_destroy(&mutex);
死锁的产生原因和产生的必要条件:
产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程和线程之间形成一种头尾相接的循环等待资源关系。
线程同步的概念
线程同步是指在多线程环境中,通过特定机制协调线程的执行顺序,避免因并发访问共享资源导致的数据不一致或竞态条件。常见的同步机制包括互斥锁、信号量、条件变量等。
信号量概述
信号量(Semaphore)是Linux中用于进程或线程间同步的机制,由E.W. Dijkstra提出。它本质上是一个计数器,用于控制对共享资源的访问。信号量分为:
- 二进制信号量:取值为0或1,类似互斥锁。
- 计数信号量:取值为非负整数,用于限制资源数量。
sem_init函数概述
sem_init
是Linux系统中用于初始化未命名信号量的函数,属于POSIX信号量 API(<semaphore.h>
)。它常用于多线程或多进程间的同步控制,通过计数器机制管理资源访问。
函数原型
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem
: 指向待初始化的信号量对象的指针。pshared
: 指定信号量的共享范围:0
:信号量在线程间共享(同一进程内)。- 非
0
:信号量在进程间共享(需放在共享内存中)。
value
: 信号量的初始计数值(通常表示资源可用数量)。value 信号量的初始值,一般无名信号量, 都是二值信号量。
0 表示红灯,进程暂停阻塞
1 表示绿灯,进程可以通过执行
返回值
- 成功:返回
0
。 - 失败:返回
-1
并设置errno
(如EINVAL
无效参数、ENOSPC
资源耗尽)。
sem_t函数基本概念
sem_t
是一个不透明的结构体类型,通常通过指针操作。它分为两种类型:
- 无名信号量:用于线程间同步,存储在共享内存中。
- 有名信号量:用于进程间同步,通过文件系统路径名标识。
常用函数
以下是与 sem_t
相关的主要函数:
初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
pshared
:0
表示线程间共享,非零表示进程间共享。value
:信号量初始值。
销毁信号量
int sem_destroy(sem_t *sem);
- 仅用于无名信号量。
sem_wait 概述
sem_wait
是 Linux 系统中用于操作信号量(semaphore)的系统调用之一,属于 POSIX 线程(pthread)库的一部分。它的主要功能是尝试减少信号量的值,如果信号量的值大于零,则减一并立即返回;如果值为零,则调用线程会被阻塞,直到信号量的值变为非零。
功能:
判断当前sem信号量是否有资源可用。
如果sem有资源(==1),则申请该资源,程序继续运行
如果sem没有资源(==0),则线程阻塞等待,一 旦有资源
则自动申请资源并继续运行程序。
注意:sem 申请资源后会自动执行 sem = sem - 1;
参数:sem 要判断的信号量资源
函数原型
#include <semaphore.h>
int sem_wait(sem_t *sem);
- 参数:
sem
是指向信号量对象的指针。 - 返回值:成功时返回 0,失败时返回 -1 并设置
errno
。
使用场景
sem_wait
通常用于线程或进程间的同步,确保对共享资源的互斥访问。常见场景包括:
- 控制临界区的进入(如共享内存、文件操作)。
- 实现生产者-消费者模型中的资源计数。
阻塞等待(P操作)
P ===》申请资源===》申请一个二值信号量
int sem_wait(sem_t *sem);
- 若信号量值为
0
,则阻塞直到值变为正。
发布(V操作)
V ===》释放资源===》释放一个二值信号量
int sem_post(sem_t *sem);
- 增加信号量值,唤醒等待线程。
获取当前值
int sem_getvalue(sem_t *sem, int *sval);
- 将当前值存入
sval
(可能因并发不准确)。
注意事项
- 进程间共享:需将信号量放在共享内存中,或使用有名信号量(如
sem_open
)。 - 错误处理:所有函数返回
-1
时表示错误,需检查errno
。 - 资源释放:确保销毁信号量以避免内存泄漏。
计数信号量:计数信号量是一种同步机制,用于控制多个线程或进程对共享资源的访问。与二进制信号量(仅0或1)不同,计数信号量允许一个整数值,表示可用资源的数量。