Linux线程 分离和同步与互斥 条件变量

Linux线程 分离和同步与互斥 条件变量

  • 1. 分离线程
  • 2. 线程互斥与互斥量
  • 3. 线程同步与竞态条件
  • 4. pthread库与条件变量
  • 5. 生产者-消费者

1. 分离线程

  1. 什么是线程分离?
    线程分离是指线程在结束时,操作系统会自动回收其资源,而无需其他线程显式地等待它的结束或调用pthread_join函数。这种机制允许主线程不必关心子线程的状态,从而提高程序的并发性和可维护性。

  2. pthread_detach函数
    pthread_detach 函数是一个用于将线程设置为分离状态的POSIX线程库函数。通过调用这个函数,线程的资源将在其终止时自动回收,无需其他线程调用 pthread_join 来等待该线程的结束。

#include <pthread.h>
int pthread_detach(pthread_t thread);

参数说明
thread:要设置为分离状态的线程标识符
返回值
成功:返回0。
失败:返回错误码,可通过 perror 函数打印出错误信息。

代码示例:

#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 3// 线程执行的任务
void *thread_function(void *arg) {int thread_id = *((int *)arg);int n = 5;// 模拟线程执行任务,循环5次while (n--) {printf("线程 %d 正在运行\n", thread_id);sleep(1);  // 每秒打印一次,模拟线程执行任务}// 线程结束pthread_exit(NULL);
}int main() {pthread_t threads[NUM_THREADS];int thread_ids[NUM_THREADS];// 创建并启动3个线程for (int i = 0; i < NUM_THREADS; ++i) {thread_ids[i] = i + 1;// 创建线程if (pthread_create(&threads[i], NULL, thread_function, (void *)&thread_ids[i]) != 0) {perror("创建线程失败");return -1;}// 设置线程为分离状态if (pthread_detach(threads[i]) != 0) {perror("设置线程为分离状态失败");return -1;}}// 主线程执行的任务while (1) {printf("主线程正在运行\n");sleep(1);  // 主线程每秒打印一次,模拟执行其他任务}return 0;
}

运行时,使用 while :; do ps -aL ;sleep 1;done 实时查看。
在这里插入图片描述

这个程序创建了3个线程,每个线程模拟执行任务5次。主线程在一个无限循环中每秒打印一次消息,模拟执行其他任务。这里使用了 pthread_create 来创建线程,pthread_detach 将线程设置为分离状态,确保线程在结束时能够自动释放资源。

2. 线程互斥与互斥量

多线程编程是一种广泛应用于提高程序性能的技术。然而,当多个线程同时访问和修改共享资源时,可能会导致数据竞争(Data Race)和其他并发问题。为了解决这些问题,互斥量(Mutex)被引入,成为多线程编程中的重要工具。

  1. 为什么需要互斥量?
    在多线程环境下,多个线程可能同时访问和修改共享资源,导致竞态条件。竞态条件是一种并发问题,可能引起不确定的行为。为了解决这些问题,我们引入互斥量来保护共享资源,确保一次只有一个线程能够访问它

  2. 临界资源与临界区
    临界资源: 多个线程执行流共享的资源称为临界资源,它可能是一块内存、文件、网络连接等。对这些资源的并发访问可能导致不确定的结果或数据损坏。
    临界区: 是每个线程内部访问临界资源的代码段。在临界区内,对共享资源的访问需要进行互斥,以确保同一时刻只有一个线程能够进入临界区

  3. 互斥与原子性
    互斥: 互斥是一种机制,确保在任何时刻只有一个线程能够进入临界区,从而访问临界资源,通常对临界资源起保护作用。
    原子性: 表示一个操作是不可中断的,要么全部执行成功,要么完全不执行。在多线程环境中,原子操作是不会被其他线程中断的操作,确保原子性可以避免竞态条件和数据不一致性。

示例程序说明(不使用互斥量):
在这里插入图片描述
上述程序输出结果表明,由于多个线程同时访问和修改共享资源(available_tickets)而没有同步机制,导致竞态条件的发生。在输出中,票数递减,并最终变成负数。由于线程执行的顺序不确定,每次运行结果可能不同。

  1. 互斥量和加锁

在这里插入图片描述

  1. pthread_mutex_t 类型
    pthread_mutex_tPOSIX 线程库提供的互斥量类型,用于在多线程环境中同步对共享资源的访问。它是一个结构体类型,通常通过指针进行操作
  2. pthread_mutex_init 函数
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

功能: 初始化互斥量对象。
参数
mutex 是指向要初始化的互斥量对象的指针。
attr 是指向互斥量属性对象的指针。可以为 NULL,表示使用默认属性。
返回值: 若成功,返回 0;否则,返回错误码

  1. pthread_mutex_destroy 函数
#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex); 

功能: 销毁互斥量对象。

参数: mutex 是指向要销毁的互斥量对象的指针。

返回值: 若成功,返回 0;否则,返回错误码。

  1. PTHREAD_MUTEX_INITIALIZER

PTHREAD_MUTEX_INITIALIZER 是一个宏,用于静态初始化一个互斥锁(mutex)。
在定义互斥量时,可以使用以下宏进行初始化:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

功能: 使用宏 PTHREAD_MUTEX_INITIALIZER 初始化互斥量对象。

注意: 此方法只能在定义互斥量时使用,不能在运行时再次初始化。

  1. pthread_mutex_lock 函数
 #include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);

功能pthread_mutex_lock 的功能是加锁,而且如果互斥量已经被锁定再次调用 pthread_mutex_lock 将会导致调用线程被阻塞,直到互斥量变为可用。

参数mutex 是指向要加锁的互斥量对象的指针。

返回值: 若成功,返回 0;否则,返回错误码。

  1. pthread_mutex_unlock 函数
 #include <pthread.h>int pthread_mutex_unlock(pthread_mutex_t *mutex);

功能: 解锁。释放互斥量,使其变为可用。

参数mutex 是指向要解锁的互斥量对象的指针。

返回值: 若成功,返回 0;否则,返回错误码。

示例程序说明(使用互斥量):
在这里插入图片描述

pthread_mutex_t mutex 主要用于保护临界区,对共享资源进行读取或修改的那部分代码。在多线程环境中,当多个线程同时访问共享资源而缺乏适当的同步机制时,可能导致数据不一致或产生竞争条件

通过调用 pthread_mutex_lockpthread_mutex_unlock
函数,程序可以执行互斥操作。在进入临界区前,线程通过加锁确保只有一个线程能够执行临界区代码。而在退出临界区后,通过解锁释放互斥锁,使其他线程有机会进入。

以上程序通过互斥量确保了多线程环境下对共享资源(票数)的安全访问,实现了线程安全的抢票操作。

3. 线程同步与竞态条件

在多线程编程中,多个线程共享进程的资源,这样就可能导致竞态条件的产生。竞态条件是由于多个线程对共享资源的访问顺序不确定而引起的问题。为了解决这一问题,引入了线程同步的概念。

程序示例(不使用线程同步)
在这里插入图片描述

从这个输出可以看出,线程2连续抢到了多张票而其他线程并没有执行抢票的机会。这是因为在没有使用线程同步的情况下,多个线程同时访问了共享资源,导致了竞态条件。

4. pthread库与条件变量

在多线程编程中,线程之间的协调与同步是至关重要的。pthread库提供了一系列工具,其中条件变量(pthread_cond_t)是一种强大的机制。

在这里插入图片描述

  1. pthread_cond_t类型
    pthread_cond_tpthread库中用于线程同步的一种机制,也被称为条件变量条件变量允许线程在等待某个条件满足时进入休眠状态,并在条件发生变化时被唤醒。条件变量通常与互斥锁一起使用,以确保多个线程对共享资源的安全访问。

  2. pthread_cond_init函数

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

功能:
pthread_cond_init 函数用于初始化条件变量,为其分配必要的资源。

参数:
cond:指向要初始化的条件变量的指针。
attr:条件变量的属性,通常设置为 NULL 表示使用默认属性。
返回值:
若成功初始化条件变量,返回 0;否则,返回错误码。

  1. pthread_cond_destroy 函数
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);

功能:
pthread_cond_destroy 函数用于销毁条件变量,释放相关资源。

参数:
cond:指向要销毁的条件变量的指针。
返回值:
若成功销毁条件变量,返回 0;否则,返回错误码。

  1. PTHREAD_MUTEX_INITIALIZER

PTHREAD_COND_INITIALIZER宏,是一种静态初始化pthread_cond_t类型的条件变量的方式。
在定义条件变量时,可以使用以下宏进行初始化:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  1. pthread_cond_wait函数
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

功能:
pthread_cond_wait 函数用于在等待条件变量的同时暂时释放互斥锁,使线程进入等待状态。

参数:
cond:指向要等待的条件变量的指针。
mutex:指向互斥锁的指针,用于保护对条件变量的访问。
返回值:
若成功,返回 0;否则,返回错误码。

  1. pthread_cond_broadcast函数
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);

功能:
pthread_cond_broadcast 函数用于向所有等待在条件变量上的线程发送信号,使它们从等待状态中唤醒。

参数:
cond:指向要发送信号的条件变量的指针。
返回值:
若成功,返回 0;否则,返回错误码。

  1. pthread_cond_signal函数
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);

功能
pthread_cond_signal 函数用于向等待在条件变量上的一个线程发送信号,使其从等待状态中唤醒。

参数
cond:指向要发送信号的条件变量的指针。
返回值
若成功,返回 0;否则,返回错误码。

程序示例(使用线程同步)
在这里插入图片描述

pthread_cond_init(&cond, NULL); 用于初始化条件变量 cond,与互斥锁一同使用,用于线程等待和唤醒。在线程执行函数中,通过 pthread_cond_wait(&cond, &mutex); 进行等待,释放互斥锁 mutex 进入阻塞状态。

主线程通过 pthread_cond_signal(&cond); 发送信号,唤醒一个等待条件变量的线程,被唤醒的线程在获取互斥锁之前不能继续执行。这确保了每个线程在唤醒后都能够争夺到互斥锁,避免了线程饥饿的情况。

5. 生产者-消费者

  1. 生产者消费者模型的概念

在这里插入图片描述

生产者消费者模型通过中间容器(阻塞队列)解决了生产者和消费者强耦合的问题。两者不直接通讯,而是通过阻塞队列传递数据。生产者产生数据后,无需等待消费者处理,直接放入阻塞队列。消费者不主动请求数据,而是直接从阻塞队列取出,阻塞队列充当了缓冲区的角色。

  1. 生产者、消费者之间的关系

在生产者消费者模型中存在三种关系:

生产者和生产者之间的互斥关系: 确保不同生产者之间的操作互斥,以保证数据的正确生成。

消费者和消费者之间的互斥关系: 确保不同消费者之间的操作互斥,防止并发访问导致问题。

生产者和消费者之间的互斥与同步关系: 实现互斥以保证读写安全,同时在缓冲区数据满或空时,确保能够互相等待和通知,实现同步操作。生产者线程和消费者线程是两种不同的角色,彼此之间通过缓冲区进行数据交流,这个缓冲区可被看作是一个特定结构的交换平台。

代码示例:

在这里插入图片描述

pthread_mutex_t mutex:互斥锁

作用: 保护对缓冲区的访问,确保在同一时刻只有一个线程能够访问或修改共享资源
使用场景: 在生产者和消费者访问缓冲区时,通过互斥锁进行加锁和解锁,避免多个线程同时修改共享资源导致数据不一致或冲突。


pthread_cond_t not_full:缓冲区不满的条件变量
作用: 用于通知生产者线程缓冲区不再是满的状态,可以继续生产数据。
使用场景: 当缓冲区满时,生产者线程通过等待该条件变量进入阻塞状态,直到消费者线程通知它缓冲区不再是满的。

pthread_cond_t not_empty:缓冲区不空的条件变量
作用: 用于通知消费者线程缓冲区不再是空的状态,可以继续消费数据。
使用场景: 当缓冲区为空时,消费者线程通过等待该条件变量进入阻塞状态,直到生产者线程通知它缓冲区不再是空的。

这个程序展示了基本的生产者-消费者模型,通过互斥锁和条件变量确保线程安全的访问共享资源。生产者不断生成随机数作为数据项并放入缓冲区,而消费者则从缓冲区中取出数据项进行消费。这种模型确保了在多线程环境中的安全数据传递和协同工作。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【开源】JAVA+Vue+SpringBoot实现公司货物订单管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 客户管理模块2.2 商品维护模块2.3 供应商管理模块2.4 订单管理模块 三、系统展示四、核心代码4.1 查询供应商信息4.2 新增商品信息4.3 查询客户信息4.4 新增订单信息4.5 添加跟进子订单 五、免责说明 一、摘要 1.1 项目…

[自然语言处理|NLP] 文本分类与情感分析,数据预处理流程,包括了同义词替换和拼写纠正,以及使用NLTK库和TextBlob库进行标记化和情感分析(附代码)

[自然语言处理|NLP] 文本分类与情感分析,数据预处理流程,包括了同义词替换和拼写纠正,以及使用NLTK库和TextBlob库进行标记化和情感分析(附代码)。 自然语言处理(Natural Language Processing,简称NLP)是人工智能领域的一个重要分支,涉及了处理和理解人类语言的技术…

百卓Smart管理平台 uploadfile.php 文件上传漏洞(CVE-2024-0939)

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

除夕日的每日一题(字符个数统计,多数元素)

字符个数统计_牛客题霸_牛客网 (nowcoder.com) #include <stdio.h> #include <string.h> #include <stdlib.h>int num0,len,i,j,k,asc; int tmp[128]{0}; char str[400]; int main() {gets(str);//gets(str) 用于从标准输入读取一个字符串并存储在 str 中len…

「递归算法」:合并两个有序链表

一、题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输出&#…

华为第二批难题一:基于预训练AI模型的元件库生成

我的理解&#xff1a;华为的这个难道应该是想通过大模型技术&#xff0c;识别元件手册上的图文内容&#xff0c;与现有建库工具结合&#xff0c;有潜力按标准生成各种库模型。 正好&#xff0c;我们正在研究&#xff0c;利用知识图谱技术快速生成装配模型&#xff0c;其中也涉…

有关网络安全的课程学习网页

1.思科网络学院 免费学习skillsforall的课程 课程链接&#xff1a;Introduction to Cybersecurity by Cisco: Free Online Course (skillsforall.com) 2.斯坦福大学计算机和网络安全基础 该证书对于初学者来说最有价值&#xff0c;它由最著名的大学之一斯坦福大学提供。您可…

基于YOLOv7算法的高精度实时老鼠目标检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算的高精度实时老鼠目标检测系统可用于日常生活中检测与定位老鼠目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训练数据…

nodejs+vue高校实验室耗材管理系统_m20vy

用户功能&#xff1a; 登录后要有一个首页 比如:可以看见目前的耗材消耗记录&#xff0c;可做成图表菜单栏在左侧显示 1.个人信息管理 可以对基本信息进行修改&#xff0c;(修改密码时需要验证) 2.耗材管理&#xff08;耗材信息&#xff09; 普通用户可以查询当前相关耗材信息[…

【数据结构与算法】力扣刷题记之 稀疏数组

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

OCP使用CLI创建和构建应用

文章目录 环境登录创建project赋予查看权限部署第一个image创建route检查pod扩展应用 部署一个Python应用连接数据库创建secret加载数据并显示国家公园地图 清理参考 环境 RHEL 9.3Red Hat OpenShift Local 2.32 登录 通过 crc console --credentials 可以查看登录信息&…

CS50x 2024 - Lecture 2 - Arrays

00:00:00 - Introduction 00:01:01 - Story Time 00:06:03 - Compiling make本身并不是编译器&#xff0c;实际上是一个自动运行编译器的程序&#xff0c;如c语言的clang clang -o hello hello.csrc/ $ clang -o hello hello_world.c /usr/bin/ld: /tmp/hello_world-67f51…

【VTKExamples::PolyData】第二十四期 InterpolateTerrain

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例InterpolateTerrain,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. InterpolateTerrain 输出: Interp…

FX110网:如何判断行情是真突破还是假突破?

众所周知&#xff0c;在交易过程中&#xff0c;趋向线的突破对买入、卖出时机等选择具有重要的分析意义。因此&#xff0c;搞清趋势线何时突破&#xff0c;是有效的突破还是非有效的突破&#xff0c;于投资者而言是至关重要的。 本文将提供一些对于趋向线突破的判断方法和市场原…

软考 系统分析师系列知识点之信息系统战略规划方法(4)

接前一篇文章&#xff1a;软考 系统分析师系列知识点之信息系统战略规划方法&#xff08;3&#xff09; 所属章节&#xff1a; 第7章. 企业信息化战略与实施 第4节. 信息系统战略规划方法 7.4.2 关键成功因素法 关键成功因素&#xff08;Critical Success Factors&#xff0c…

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程、Spark新特性

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 Spark新特性 自适应查询(SparkSQL) 动态合并 动态调整Join策略 …

Redis篇之持久化

一、为什么要进行持久化 Redis是一个基于内存的键值存储系统&#xff0c;但为了保证数据在服务器重启、故障等情况下不丢失。 二、应该怎么持久化 1.RDB持久化 &#xff08;1&#xff09;RDB是什么 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff…

Android性能调优 - 应用安全问题

Android应用安全 1.组件暴露&#xff1a; 像比如ContentProvider,BroadcastReceiver&#xff0c;Activity等组件有android:exported属性&#xff1b; 如果是私有组件 android:exported “false”&#xff1b; 如果是公有组件 android:exported “true” 且进行权限控制&…

[BeginCTF]真龙之力

安装程序 双击安装 出现了安装失败的标签&#xff0c;开发者不允许测试。 查看Mainfest入口文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android" android:versionCo…

【Spring源码解读!底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;底层原理高级进阶》 &#x1f680…