C语言多线程编程-线程同步

介绍

多线程编程,经常会遇到线程直接数据同步,为了保证数据访问安全,就必须考虑线程之间的同步问题。在C语言中,多线程编程的线程同步主要依赖于POSIX线程(Pthreads)库提供的同步原语。以下是一些关键的线程同步机制:

  1. 互斥锁 (Mutexes)

    • pthread_mutex_t 是一种互斥对象,用于保护共享资源,确保同一时间只有一个线程可以访问。
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
    pthread_mutex_lock(&mutex);       // 上锁
    // 访问共享资源的代码
    pthread_mutex_unlock(&mutex);     // 解锁
    
  2. 读写锁 (Read-Write Locks)

    • pthread_rwlock_t 允许多个线程同时进行读取操作,但在写入操作时会排斥所有其他读写线程。
    pthread_rwlock_t rwlock;
    pthread_rwlock_init(&rwlock, NULL);
    pthread_rwlock_rdlock(&rwlock);  // 读取锁定
    // 读取共享资源的代码
    pthread_rwlock_unlock(&rwlock);  // 释放锁定
    pthread_rwlock_wrlock(&rwlock);  // 写入锁定
    // 更新共享资源的代码
    pthread_rwlock_unlock(&rwlock);  // 释放锁定
    
  3. 条件变量 (Condition Variables)

    • 条件变量 pthread_cond_t 与互斥锁结合使用,允许线程阻塞等待特定条件变为真。
    pthread_cond_t cond;
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);pthread_mutex_lock(&mutex);
    while (!condition_is_true()) { // 检查条件pthread_cond_wait(&cond, &mutex); // 条件不满足则等待
    }
    // 当条件满足时执行相关操作
    pthread_mutex_unlock(&mutex);// 另一个线程改变条件后,可以唤醒等待的线程
    pthread_mutex_lock(&mutex);
    condition_make_true(); // 改变条件
    pthread_cond_signal(&cond); // 唤醒一个等待线程
    // 或者唤醒所有等待线程
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mutex);
    
  4. 信号量 (Semaphores)

    • POSIX信号量 sem_t 也可以用于同步线程,它是一个计数器,控制可以同时访问资源的线程数量。
    sem_t semaphore;
    sem_init(&semaphore, 0, 1); // 初始化为1,即一次只允许一个线程通过sem_wait(&semaphore); // 阻塞直到信号量计数大于0并减一
    // 执行临界区代码
    sem_post(&semaphore); // 信号量加一,释放资源
    

应用举例

以下是一个使用互斥锁(Mutexes)和条件变量(Condition Variables)实现的简单生产者-消费者问题的例子。生产者线程生成数据并放入缓冲区,消费者线程从缓冲区取出数据处理。

#include <pthread.h>
#include <stdio.h>#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int buffer_count = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;void* producer(void* arg) {int i;for (i = 0; i < 20; i++) {pthread_mutex_lock(&mutex);while (buffer_count == BUFFER_SIZE) { // 如果缓冲区已满pthread_cond_wait(&full, &mutex); // 生产者等待}buffer[buffer_count++] = i; // 放入数据printf("Producer produced %d\n", i);pthread_cond_signal(&empty); // 唤醒消费者pthread_mutex_unlock(&mutex);}return NULL;
}void* consumer(void* arg) {int i;while (1) {pthread_mutex_lock(&mutex);while (buffer_count == 0) { // 如果缓冲区为空pthread_cond_wait(&empty, &mutex); // 消费者等待}int data = buffer[--buffer_count]; // 取出数据printf("Consumer consumed %d\n", data);pthread_cond_signal(&full); // 唤醒生产者pthread_mutex_unlock(&mutex);// 在这里可以处理消费的数据,这里为了简化直接输出}return NULL;
}int main() {pthread_t producer_thread, consumer_thread;pthread_create(&producer_thread, NULL, producer, NULL);pthread_create(&consumer_thread, NULL, consumer, NULL);pthread_join(producer_thread, NULL);pthread_join(consumer_thread, NULL);pthread_cond_destroy(&full);pthread_cond_destroy(&empty);pthread_mutex_destroy(&mutex);return 0;
}
示例说明

在这个例子中,创建了两个线程:一个生产者线程和一个消费者线程。生产者在缓冲区未满时产生数据,并通过条件变量full通知消费者;消费者在缓冲区非空时消费数据,并通过条件变量empty通知生产者。通过互斥锁mutex保护对共享资源(缓冲区和缓冲区计数器)的访问,确保了线程间的同步。

总结

在使用这些同步机制时,重要的是要理解它们各自的适用场景和潜在的开销。不恰当的同步可能导致性能下降或死锁等问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevOps(6)

目录 26.如何在Linux下跨不同的虚拟桌面共享程序&#xff1f; 27.无名&#xff08;空&#xff09;目录代表什么&#xff1f; 29.什么是守护进程&#xff1f; 30.如何从一个桌面环境切换到另一个桌面环境&#xff0c;例如从KDE切换到Gnome? 26.如何在Linux下跨不同的虚拟桌面…

你的网站或许不需要前端构建(二)

前一阵&#xff0c;有朋友问我&#xff0c;能否在不进行前端编译构建的情况下&#xff0c;用现代语法开发网站界面。 于是&#xff0c;就有了这篇文章中提到的方案。 写在前面 这篇文章&#xff0c;依旧不想讨论构建或不构建&#xff0c;哪一种方案对开发更友好&#xff0c;…

JavaScript实现大整数加法

实现大整数加法 即两个数字字符相加&#xff0c;采用按位加法实现 方法 const add (a, b) > {let i a.length - 1;let j b.length - 1;let carry 0;let ret "";while (i > 0 || j > 0) {let x 0;let y 0;let sum "";if (i > 0) {x …

《工具录》NetCat

工具录 1&#xff1a;NetCat2&#xff1a;选项介绍3&#xff1a;示例3.1&#xff1a;正向连接&#xff08;被动连接&#xff09;3.2&#xff1a;反向连接&#xff08;主动连接&#xff09;3.3&#xff1a;信息收集3.4&#xff1a;文件传输 4&#xff1a;其他 本文以 kali-linux…

MySQL——视图

目录 一.视图介绍 二.基本使用 三.视图规则和限制 一.视图介绍 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 二.基本使用 创…

在 list 中根据项目需求,使用不同的方法进行查找及删除

学习目标&#xff1a; 学习目标 在 list 中根据项目需求&#xff0c;使用不同的方法进行查找及删除 学习内容&#xff1a; 内容 在 list 中根据项目需求&#xff0c;使用不同的方法进行查找在 list 中根据项目需求&#xff0c;使用不同的方法进行删除 知识总结&#xff1a; …

【mysql django】解决Django提示mysql版本过低

目录 一、解决Django提示mysql版本过低&#xff1a;django.db.utils.NotSupportedError: MySQL 8 or later is required (found 5.7.26) 一、解决Django提示mysql版本过低&#xff1a;django.db.utils.NotSupportedError: MySQL 8 or later is required (found 5.7.26) 报错&…

Netty初探:掌握高性能网络通信框架,提升Java网络编程技能

Netty初探 NIO 的类库和 API 繁杂 &#xff0c; 使用麻烦&#xff1a; 需要熟练掌握Selector、 ServerSocketChannel、SocketChannel、 ByteBuffer等。 开发工作量和难度都非常大&#xff1a; 例如客户端面临断线重连、 网络闪断、心跳处理、半包读写、 网络拥塞和异常流的处…

左旋字符串与判断字符串左旋编程题

字符串左旋 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 方法一 void left_move(char* arr, int k) {int i 0;size_t len strlen(arr);k k % len;for (i 0; i < k; i){//左旋转一个…

30 C++ 类型转换构造函数 和 类型转换函数 operator type(类对象)

类型转换构造函数 定义 //类型转换构造函数&#xff1a; //只有一个参数的构造函数&#xff0c; //且参数不是自己的const 引用的构造函数&#xff0c;也称之为 &#xff1a;类型转换构造函数。 //类型转换构造函数&#xff1a; //只有一个参数的构造函数&#xff0c; //且参数…

2.C++的编译:命令行、makefile和CMake

1. 命令行编译 命令行编译是指直接在命令行中输入以下指令&#xff1a; 预处理&#xff1a;gcc -E main.c -o main.i 编译&#xff1a;gcc -S main.i -o main.s 汇编&#xff1a;gcc -c main.s -o main.o 链接&#xff1a;gcc main.o -o main 命令汇总&#xff1a;gcc main.c …

JVM篇:直接内存

直接内存 直接内存并不是JVM的内存结构&#xff0c;直接内存是操作系统的内存&#xff0c;Java本身并不能对操作系统的内存进行操作&#xff0c;而是通过调用本地方法。直接内存常用于NIO作为缓冲区存在&#xff0c;分配成本较高但是读写性能好&#xff0c;并且不受JVM内存回收…

FingerprintService启动-Android13

FingerprintService启动-Android13 1、指纹服务启动1.1 rc启动Binder对接指纹厂商TA库1.2 FingerprintService启动1.2.1 SystemServer启动FingerprintService1.2.2 注册Binder服务fingerprint 2、获取底层信息2.1 AIDL 对接TA中获取2.2 指纹类型判断 android13-release 1、指纹…

PyTorch基础操作

一、Tensor 在 PyTorch 中&#xff0c;张量&#xff08;Tensor&#xff09;是一个核心概念&#xff0c;它是一个用于存储和操作数据的多维数组&#xff0c;类似于 NumPy 的 ndarray&#xff0c;但与此同时&#xff0c;它也支持 GPU 加速&#xff0c;这使得在大规模数据上进行科…

CSS 放大翻转动画

<template><div class="container" @mouseenter="startAnimation" @mouseleave="stopAnimation"><!-- 旋方块 --><div class="box" :class="{ rotate-scale-up-hor: isAnimating }"><!-- 元素内…

F# 中更安全的递归

作者&#xff1a;David Schaefer 排版&#xff1a;Alan Wang 这是 David Schaefer 的客座博客文章。David 是一名专注于函数式编程的自由软件开发人员。他是 G-Research 开源团队的一员。他致力于改进 F# 开发者工具的生态系统。此外&#xff0c;他还帮助维护各种开源的 F# 项目…

使用爬虫爬取热门电影

文章目录 网站存储视频的原理M3U8文件解读网站分析代码实现 网站存储视频的原理 首先我们来了解一下网站存储视频的原理。 一般情况下&#xff0c;一个网页里想要显示出一个视频资源&#xff0c;必须有一个<video>标签&#xff0c; <video src"xxx.mp4"&…

【Python_PyQtGraph 学习笔记(九)】基于PlotWidget实现plot对象的坐标点添加标签

基于PlotWidget实现plot对象的坐标点添加标签 前言正文1、f_plotAddMark(self, xLst, yLst) 方法1、方法传参介绍2、方法内参数介绍2、方法调用3、案例完整代码4、实现效果前言 本文介绍如何在 PlotWidget 的 plot 对象坐标点上添加标签,也可以说是在 PlotWidget 上添加点的标…

Note: A Journey Across Canada

A Journey Across Canada 一场横穿加拿大的旅行 across journey After a quiz last autumn, Kuang crossed the continent eastward to Toronto to visit his schoolmate, the distance measuring approximately 5000 kilometers. 去年秋天一次考试后&#xff0c;Kuang向东穿…

数字人克隆系统开发公司?

广州硅基技术开发限公司是一家位于中国广东省广州市的科技公司。该公司专注于人工智能&#xff08;AI&#xff09;领域的研发和创新。广州硅基以技术创新和解决方案为核心&#xff0c;致力于为客户提供高质量的人工智能产品和服务。 广州硅基技术的主要业务包括但不限于&#…