news 2026/4/16 0:24:17

应用——线程竞争资源模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
应用——线程竞争资源模型

多线程并发编程笔记:线程竞争资源模型

一、代码示例对比分析

示例1:带线程ID的窗口竞争模型

#include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h> #include <time.h> int win = 3; // 可用窗口数 pthread_mutex_t mutex; void *th(void *arg) { int id = *(int *)arg; // 获取线程ID sleep(rand() % 5); // 随机延迟0-4秒 while (1) // 持续尝试直到成功 { pthread_mutex_lock(&mutex); if(win > 0) // 检查是否有可用窗口 { win--; // 占用一个窗口 pthread_mutex_unlock(&mutex); printf("%d:get win\n", id); // 显示获取成功 sleep(rand() % 3 + 1); // 模拟使用窗口1-3秒 pthread_mutex_lock(&mutex); win++; // 释放窗口 pthread_mutex_unlock(&mutex); printf("%d:relese win\n", id); // 显示释放 break; // 退出循环 } else { printf("%d: 没有可用窗口,等待...\n", id); pthread_mutex_unlock(&mutex); sleep(1); // 等待1秒后重试 } } return NULL; } int main(int argc, char **argv) { srand(time(NULL)); // 初始化随机种子 pthread_t tid[10]; // 线程ID数组 int id[10]; // 线程编号数组 // 初始化线程编号 for (int i = 0; i < 10; i++) { id[i] = i + 1; } pthread_mutex_init(&mutex, NULL); // 初始化互斥锁 // 创建10个线程 for (int i = 0; i < 10; i++) { pthread_create(&tid[i], NULL, th, &id[i]); } // 等待所有线程结束 for (int i = 0; i < 10; i++) { pthread_join(tid[i], NULL); } pthread_mutex_destroy(&mutex); // 销毁互斥锁 return 0; }

示例2:匿名线程竞争模型

#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> int win = 3; // 可用窗口数 pthread_mutex_t mutex; void* th(void* arg) { while (1) { pthread_mutex_lock(&mutex); if (win > 0) // 检查是否有可用窗口 { win--; // 占用窗口 pthread_mutex_unlock(&mutex); printf("get win...\n"); // 获取成功 sleep(rand() % 5 + 1); // 使用窗口1-5秒 pthread_mutex_lock(&mutex); win++; // 释放窗口 printf("relese win...\n"); pthread_mutex_unlock(&mutex); break; // 完成任务 } else { pthread_mutex_unlock(&mutex); // 这里没有等待逻辑,会快速重试 } } return NULL; } int main(int argc, char** argv) { int i = 0; srand(time(NULL)); // 初始化随机种子 pthread_t tid[10] = {0}; // 线程ID数组 pthread_mutex_init(&mutex, NULL); // 初始化互斥锁 // 创建10个线程 for (i = 0; i < 10; i++) { pthread_create(&tid[i], NULL, th, NULL); // 不传递参数 } // 等待所有线程结束 for (i = 0; i < 10; i++) { pthread_join(tid[i], NULL); } pthread_mutex_destroy(&mutex); // 销毁互斥锁 return 0; }

示例3:多互斥锁竞争模型(trylock实现)

#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> pthread_mutex_t mutex1; // 窗口1的锁 pthread_mutex_t mutex2; // 窗口2的锁 pthread_mutex_t mutex3; // 窗口3的锁 void* th(void* arg) { int ret = 0; while (1) { // 尝试获取窗口1 ret = pthread_mutex_trylock(&mutex1); if (0 == ret) { printf("get win1...\n"); sleep(rand() % 5 + 1); printf("release win1...\n"); pthread_mutex_unlock(&mutex1); break; } else { // 尝试获取窗口2 ret = pthread_mutex_trylock(&mutex2); if (0 == ret) { printf("get win2...\n"); sleep(rand() % 5 + 1); printf("release win2...\n"); pthread_mutex_unlock(&mutex2); break; } else { // 尝试获取窗口3 ret = pthread_mutex_trylock(&mutex3); if (0 == ret) { printf("get win3...\n"); sleep(rand() % 5 + 1); printf("release win3...\n"); pthread_mutex_unlock(&mutex3); break; } else { // 所有窗口都忙,可以添加等待逻辑 // 当前版本会忙等待 } } } } return NULL; } int main(int argc, char** argv) { int i = 0; srand(time(NULL)); pthread_t tid[10] = {0}; pthread_mutex_init(&mutex1, NULL); pthread_mutex_init(&mutex2, NULL); pthread_mutex_init(&mutex3, NULL); for (i = 0; i < 10; i++) { pthread_create(&tid[i], NULL, th, NULL); } for (i = 0; i < 10; i++) { pthread_join(tid[i], NULL); } pthread_mutex_destroy(&mutex1); pthread_mutex_destroy(&mutex2); pthread_mutex_destroy(&mutex3); return 0; }

二、三种模型对比分析

1.设计思路对比

模型

核心思想

资源表示

竞争方式

模型1

集中式管理

计数器(win)

所有线程竞争一个锁,检查计数器

模型2

简化集中式

计数器(win)

同上,但无线程ID和等待消息

模型3

分布式管理

三个独立锁

每个窗口独立锁,trylock轮询

2.实现复杂度对比

模型

锁数量

代码复杂度

灵活性

模型1

1个互斥锁

中等

窗口数量易扩展

模型2

1个互斥锁

简单

功能最简

模型3

3个互斥锁

较高

每个窗口独立控制

3.性能特点对比

模型锁竞争公平性并发度
模型1高(一个锁)FIFO近似公平
模型2高(一个锁)不确定
模型3低(三个锁)优先抢占

三、关键技术点详解

1.pthread_mutex_trylock 使用

int ret = pthread_mutex_trylock(&mutex); // 返回值: // 0: 成功获取锁 // EBUSY: 锁已被占用 // 其他: 错误

2.锁的初始化与销毁

// 初始化 pthread_mutex_init(&mutex, NULL); // 或静态初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 销毁 pthread_mutex_destroy(&mutex);

3.线程创建与等待

// 创建线程 pthread_create(&tid[i], NULL, thread_func, &arg); // 等待线程结束 pthread_join(tid[i], NULL);

四、问题与改进

1.问题

示例1.2问题
Q1: 为什么线程执行顺序不确定?
  • 操作系统线程调度具有随机性

  • sleep(rand() % 5)引入随机延迟

  • 锁竞争结果不确定

Q2: 如何保证线程安全?
  • 使用互斥锁保护所有共享资源访问

  • 确保加锁和解锁配对出现

  • 避免在临界区内进行耗时操作

Q3: 为什么需要pthread_join
  • 等待线程完成,防止主线程提前退出

  • 回收线程资源

  • 确保所有任务完成

Q4: 如何优化性能?
  • 减少临界区内的操作

  • 使用读写锁(如果适用)

  • 考虑无锁数据结构

示例3的问题
  1. 忙等待问题:所有窗口都忙时,线程会快速轮询,消耗CPU

  2. 饥饿问题:可能某些线程永远抢不到窗口

  3. 优先级固定:总是先尝试窗口1,然后是2、3

2.改进方案:

// 改进版:添加随机等待和公平性 void* th_improved(void* arg) { int ret = 0; int try_count = 0; while (1) { // 随机选择尝试顺序,提高公平性 int order[3] = {0, 1, 2}; shuffle(order, 3); // 随机打乱顺序 for (int i = 0; i < 3; i++) { pthread_mutex_t* mutexes[3] = {&mutex1, &mutex2, &mutex3}; ret = pthread_mutex_trylock(mutexes[order[i]]); if (0 == ret) { printf("get win%d...\n", order[i]+1); sleep(rand() % 5 + 1); printf("release win%d...\n", order[i]+1); pthread_mutex_unlock(mutexes[order[i]]); return NULL; } } // 所有窗口都忙,指数退避等待 try_count++; int wait_time = (1 << try_count); // 指数增长 if (wait_time > 8) wait_time = 8; printf("all windows busy, waiting %d seconds...\n", wait_time); sleep(wait_time); } return NULL; }

五、应用场景建议

1.使用模型1(计数器)的场景:

  • 资源完全同质化

  • 需要精确控制资源总数

  • 扩展性要求高(窗口数量可能变化)

2.使用模型2(简化版)的场景:

  • 快速原型开发

  • 调试和演示

  • 资源竞争不激烈

3.使用模型3(多锁)的场景:

  • 资源有差异(如不同服务窗口)

  • 需要高并发性能

  • 可以接受一定的不公平性

六、最佳实践总结

  1. 根据需求选模型

    • 同质资源 → 计数器模型

    • 异质资源 → 多锁模型

    • 简单场景 → 简化模型

  2. 避免忙等待

    • trylock失败后适当sleep

    • 使用指数退避策略

    • 考虑使用条件变量

  3. 确保资源释放

    • 每个lock都要有对应的unlock

    • 所有退出路径都要释放锁

    • 主线程等待所有子线程

  4. 错误处理

    • 检查pthread函数返回值

    • 添加适当的日志输出

    • 考虑线程安全的错误处理

  5. 性能优化

    • 减少临界区大小

    • 避免在锁内进行IO操作

    • 根据竞争程度调整策略

七、扩展思考

  1. 信号量替代方案:可以使用信号量(semaphore)更简洁地实现资源计数

  2. 条件变量:使用条件变量避免忙等待,节省CPU资源

  3. 线程池:对于频繁创建销毁的场景,考虑使用线程池

这个模型是多线程编程的基础模式,广泛应用于:

  • 数据库连接池

  • 网络服务器连接管理

  • 生产者消费者问题

  • 资源池管理等场景

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 10:45:28

【无人机】采用最基本的自由空间路损模型并且不考虑小尺度衰落(多径多普勒)固定翼无人机轨迹规划附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知,完整Matlab代码获取及仿…

作者头像 李华
网站建设 2026/4/13 15:58:05

Agent学习——小米MiMo-V2-Flash使用方法

一、MiMo-V2-Flash的亮点 ①API 定价为输入 $0.1/M tokens&#xff0c;输出 $0.3/M tokens&#xff0c;且目前限时免费&#xff0c;推理成本仅为Claude 4.5 Sonnet的2.5%。 ②在多个Agent测评基准中保持全球开源模型Top 2&#xff0c;代码能力强。 ③使用场景多为智能通场景设计…

作者头像 李华
网站建设 2026/4/16 11:05:35

safe_sleep.sh: GitHub Actions Runner 中那个偶尔无限挂起的“小睡眠”脚本

在 GitHub Actions Runner 代码库里&#xff0c;有一个看似简单的 Bash 脚本——safe_sleep.sh&#xff0c;它负责让 Runner 在某些场景下“安全地睡眠”一段时间。但这个小脚本却因为一个 subtle 的逻辑缺陷&#xff0c;让许多开发者和 CI 系统管理员困扰不已&#xff0c;甚至…

作者头像 李华
网站建设 2026/4/15 12:36:14

SiYuan知识管理终极指南:从零开始搭建个人知识库

SiYuan知识管理终极指南&#xff1a;从零开始搭建个人知识库 【免费下载链接】siyuan A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. 项目地址: https://gitcode.com/GitHub_Trending/si/siy…

作者头像 李华
网站建设 2026/4/16 12:15:01

从0到1:东南亚跑腿配送平台的技术架构

东南亚已成为全球增长最快的数字经济体之一。根据谷歌、淡马锡和贝恩公司联合发布的报告&#xff0c;东南亚互联网经济规模预计在2025年将达到3630亿美元。在这个蓬勃发展的市场中&#xff0c;跑腿配送服务作为“最后一公里”解决方案的核心环节&#xff0c;正吸引着大量创业者…

作者头像 李华