当前位置: 首页 > ds >正文

在多线程编程里,若要强制两个线程按特定次序访问相同内存区域,可借助多种同步机制达成

在多线程编程里,若要强制两个线程按特定次序访问相同内存区域,可借助多种同步机制达成。下面介绍几种常见方法,并给出 C 语言示例代码。

  1. 使用互斥锁和条件变量
    互斥锁用于保证同一时刻仅有一个线程能访问共享资源,条件变量用于线程间的同步通信。一个线程完成操作后,借助条件变量通知另一个线程继续执行。
#include <stdio.h>
#include <pthread.h>
#include <assert.h>// 定义互斥锁和条件变量
pthread_mutex_t mutex;
pthread_cond_t cond;
int turn = 0;// 共享内存区域
int shared_memory = 0;// 第一个线程函数
void *thread1(void *arg) {// 加锁pthread_mutex_lock(&mutex);// 如果turn!=0,进入等待状态,同时释放锁while (turn != 0) {pthread_cond_wait(&cond, &mutex);}// 访问共享内存shared_memory = 10;printf("Thread 1 accessed shared memory: %d\n", shared_memory);// 改变轮次turn = 1;// 通知另一个线程pthread_cond_signal(&cond);// 解锁pthread_mutex_unlock(&mutex);return NULL;
}// 第二个线程函数
void *thread2(void *arg) {// 加锁pthread_mutex_lock(&mutex);// 如果turn!=1,进入等待状态,同时释放锁while (turn != 1) {pthread_cond_wait(&cond, &mutex);}// 访问共享内存shared_memory += 20;printf("Thread 2 accessed shared memory: %d\n", shared_memory);// 改变轮次turn = 0;// 通知另一个线程pthread_cond_signal(&cond);// 解锁pthread_mutex_unlock(&mutex);return NULL;
}int main() {// 初始化互斥锁和条件变量int mutex_ret = pthread_mutex_init(&mutex, NULL);int cond_ret = pthread_cond_init(&cond, NULL);assert(mutex_ret == 0 && cond_ret == 0);pthread_t t1, t2;// 创建线程int create_ret1 = pthread_create(&t1, NULL, thread1, NULL);int create_ret2 = pthread_create(&t2, NULL, thread2, NULL);assert(create_ret1 == 0 && create_ret2 == 0);// 等待线程结束pthread_join(t1, NULL);pthread_join(t2, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

输出:

Thread 1 accessed shared memory: 10
Thread 2 accessed shared memory: 30

  1. 使用原子操作和内存顺序
    借助原子操作和合适的内存顺序,能保证线程按特定次序访问共享内存。
#include <stdatomic.h>
#include <pthread.h>
#include <stdio.h>atomic_int flag = ATOMIC_VAR_INIT(0);
int shared_memory = 0;// 第一个线程函数
void *thread1(void *arg) {// 访问共享内存shared_memory = 10;printf("Thread 1 accessed shared memory: %d\n", shared_memory);// 释放操作,保证前面的写操作完成atomic_store_explicit(&flag, 1, memory_order_release);return NULL;
}// 第二个线程函数
void *thread2(void *arg) {// 获得操作,保证后面的读操作在 flag 改变后执行while (!atomic_load_explicit(&flag, memory_order_acquire));// 访问共享内存shared_memory += 20;printf("Thread 2 accessed shared memory: %d\n", shared_memory);return NULL;
}int main() {pthread_t t1, t2;// 创建线程if (pthread_create(&t1, NULL, thread1, NULL) != 0) {perror("pthread_create for thread1");return 1;}if (pthread_create(&t2, NULL, thread2, NULL) != 0) {perror("pthread_create for thread2");return 1;}// 等待线程结束if (pthread_join(t1, NULL) != 0) {perror("pthread_join for thread1");return 1;}if (pthread_join(t2, NULL) != 0) {perror("pthread_join for thread2");return 1;}return 0;
}

输出:

Thread 1 accessed shared memory: 10
Thread 2 accessed shared memory: 30

代码解释

  • atomic_store_explicit 使用 memory_order_release 内存顺序,保证在设置 flag
    之前,shared_memory 的写操作已完成。
  • atomic_load_explicit 使用 memory_order_acquire 内存顺序,保证在 flag 改变后,才会访问
    shared_memory。

总结

  • 互斥锁和条件变量:适用于复杂的同步场景,能灵活控制线程执行顺序,但实现相对复杂,有一定性能开销。
  • 原子操作和内存顺序:实现简单,性能较高,适合对性能要求高且同步逻辑相对简单的场景。
http://www.xdnf.cn/news/9763.html

相关文章:

  • Linux软链接的目的
  • 召回增强RAPTOR策略
  • 响应式布局进阶:企业商城系统复杂交互页面的多端适配方案
  • Python训练打卡Day36
  • flutter加载dll 报错问题
  • Cesium实现标注动画
  • SMME 2025:创新海洋工程模式,迎接未来挑战
  • 深入解析 CountDownLatch、Semaphore 和CyclicBarrier
  • NHANES指标推荐:CircS
  • 3D LUT--颜色魔方
  • 生物化学:药品药物 营养和补充剂信息 第三方认证信息 常见误区 汇总
  • VirtualBox怎样安装Win10
  • 直角坐标系下 dxdy 微小矩形面积
  • 硬盘驱动器习题解析
  • 力扣刷题 -- 20.有效的括号
  • NR[ RF - 简介 ]
  • Docker Desktop无法在windows低版本进行安装
  • Qt 的简单示例 -- 地址簿
  • XCTF-web-fileinclude
  • maven离线将jar包导入到本地仓库中
  • 【大模型原理与技术-毛玉仁】第一章 语言模型基础
  • STM32F103_Bootloader程序开发04 - App跳转模块(app_jump.c与app_jump.h)
  • 使用 Unsloth 快速微调 LLMs 实用指南
  • CentOS7安装WVP+ZLM
  • 设置随机数种子的作用
  • 智慧康养实训室建设方案:基于“互联网 + 康养”的实训设计​
  • 【IEEE出版| 高届数EI会议】第十届计算机与信息处理技术国际学术研讨会(ISCIPT 2025)
  • 高并发订单服务库存超卖解决方案
  • 题目 3342: 蓝桥杯2025年第十六届省赛真题-红黑树
  • 电动黄油枪行业数据分析报告2025-恒州诚思