大模型Function Calling原理与工程实践:从面试考点到生产系统
2026/7/18 7:09:26
在多线程开发中,互斥和同步是解决 “资源竞争” 与 “执行顺序” 问题的核心技术,本文结合原理 + 代码 + 图示详细解析。
多线程并发执行时,若同时操作临界资源,会出现数据不一致:比如线程 A 执行A += 1(实际是 “读 A→运算→写 A” 三步),但线程 B 可能在 A “读” 和 “写” 之间插入操作,导致最终结果错误。
通过互斥锁(Mutex)保证 “临界区代码” 的原子性(同一时刻只有一个线程执行)。
定义互斥锁
初始化互斥锁
加锁(进入临界区)
执行临界区代码
解锁(退出临界区)
销毁互斥锁
定义互斥锁
初始化互斥锁
加锁(进入临界区)
执行临界区代码
解锁(退出临界区)
销毁互斥锁
互斥锁相关函数(POSIX 标准)
运行
// 1. 定义互斥锁 pthread_mutex_t mutex; // 2. 初始化互斥锁 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); // 参数:attr=NULL表示默认属性;返回值:成功0/失败非0 // 3. 加锁(阻塞等待,直到拿到锁) int pthread_mutex_lock(pthread_mutex_t *mutex); // 说明:加锁后,其他线程无法进入临界区 // 4. 解锁 int pthread_mutex_unlock(pthread_mutex_t *mutex); // 说明:解锁后,其他线程可竞争锁 // 5. 销毁互斥锁 int pthread_mutex_destroy(pthread_mutex_t *mutex);同步是带顺序的互斥—— 不仅要 “排他访问资源”,还要保证 “线程按指定顺序执行”。
关系:互斥是同步的超集,同步是互斥的一个特例。
信号量(Semaphore)是一种 “计数器”,通过P/V操作控制资源的 “申请” 与 “释放”,既可以实现互斥,也可以实现同步。
定义信号量
初始化信号量
P操作(申请资源)
执行代码
V操作(释放资源)
销毁信号量
定义信号量
初始化信号量
P操作(申请资源)
执行代码
V操作(释放资源)
销毁信号量
信号量相关函数(POSIX 标准)
运行
// 1. 定义信号量 sem_t sem; // 2. 初始化信号量 int sem_init(sem_t *sem, int pshared, unsigned int value); // 参数: // - pshared:0=线程间共享;非0=进程间共享 // - value:信号量初始值(资源数量) // 返回值:成功0/失败-1 // 3. P操作(申请资源:sem -= 1) int sem_wait(sem_t *sem); // 说明:若sem>0,直接减1并执行;若sem=0,阻塞等待 // 4. V操作(释放资源:sem += 1) int sem_post(sem_t *sem); // 说明:释放后,唤醒等待的线程 // 5. 销毁信号量 int sem_destroy(sem_t *sem);| 特性 | 互斥(Mutex) | 同步(Semaphore) |
|---|---|---|
| 核心目标 | 保护临界资源,避免竞争 | 控制线程执行顺序 |
| 资源数量 | 仅支持 “1 个资源” 的排他访问 | 支持 “多个资源” 的并发访问(value>1) |
| 操作主体 | 加锁 / 解锁必须是同一个线程 | P/V 操作可以是不同线程 |
| 临界区代码 | 必须短小(不能 sleep) | 可包含耗时操作(适当 sleep) |
当多个线程互相等待对方持有的资源时,会陷入 “永久阻塞” 状态,这就是死锁。