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

news2024/11/26 21:28:39

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://www.coloradmin.cn/o/1451048.html

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

相关文章

SpringMVC-入门

1.概念 SpringMVC是一种软件架构思想&#xff0c;把软件按照模型(Model)、视图(View)、控制器(Controller)这三层来划分。Model&#xff1a;指的是工程中JavaBean&#xff0c;用来处理数据View&#xff1a;指的是工程中的html、jsp等页面&#xff0c;用来展示给用户数据Control…

LGAMEFI基于BPL公链开发的第一生态:开启RWA游戏娱乐与DeFi融合的新纪元

在去中心化金融&#xff08;DeFi&#xff09;与游戏娱乐的结合趋势中&#xff0c;BPL公链上的LGAMEFI项目代表了前沿的技术革新和市场领导。这种将web2上成熟页游进行RWA链改&#xff0c;不仅仅是将游戏热门领域融合&#xff0c;更是在寻找一种全新的参与者经验&#xff0c;将玩…

Linux网络编程——tcp套接字

文章目录 主要代码关于构造listen监听accepttelnet测试读取信息掉线重连翻译服务器演示 本章Gitee仓库&#xff1a;tcp套接字 主要代码 客户端&#xff1a; #pragma once#include"Log.hpp"#include<iostream> #include<cstring>#include<sys/wait.h…

C# CAD2016 判断多边形的方向正时针或逆时针旋转

方法一&#xff1a;基于相邻顶点相对位置判断顺时针排列 // 计算当前子序列是否为顺时针排列 for (int i 1; i < outerPoints.Count; i) {int index (startVertexIndex i) % outerPoints.Count;int prevIndex (startVertexIndex i - 1) % outerPoints.Count;Point2d c…

Acwing---873. 欧拉函数

欧拉函数 1.题目2.基本思想3.代码实现 1.题目 给定 n 个正整数 ai&#xff0c;请你求出每个数的欧拉函数。 欧拉函数的定义 输入格式 第一行包含整数 n n n。 接下来 n n n 行&#xff0c;每行包含一个正整数 a i ai ai。 输出格式 输出共 n n n 行&#xff0c;每行输出…

Fluke ADPT 连接器新增对福禄克万用 Fluke 101 的支持

所需设备&#xff1a; 1、Fluke ADPT连接器&#xff1b; 2、Fluke 101&#xff1b; Fluke 101 拆机图&#xff1a; 显示界面如下图&#xff1a; 并且可以将波形导出到EXCEL: 福禄克万用表需要自己动手改造&#xff01;&#xff01;&#xff01;

电商+支付双系统项目------设计数据库

这篇文章将详细介绍电商支付双系统项目的数据库设计。数据库在该项目中扮演着至关重要的角色&#xff0c;它负责存储和管理用户信息、商品数据、订单记录以及支付交易等关键数据。通过精心设计和优化数据库结构&#xff0c;可以实现高效的数据存储和检索&#xff0c;确保系统的…

【Linux】 Linux 小项目—— 进度条

进度条 基础知识1 \r && \n2 行缓冲区3 函数介绍 进度条实现版本 1代码实现运行效果 版本2 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 基础知识 1 \r &&a…

利用修改邻接变量

资源下载 【免费】突破密码认证程序&#xff08;修改邻接变量&#xff09;资源-CSDN文库 资源内容 源码 /*****************************************************************************To be the apostrophe which changed "Impossible" into "Im possib…

java.lang.NoClassDefFoundError: org/springframework/core/GenericTypeResolver

前言 小编我将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注一下&#xff01; 也许一个人独行&#xff0c;可以走的很快&#xff0c;但是一群人结伴而行&#xff0c;才能走的更远&#xff01;让我们在成长的道路上互相学习&…

Codeforces Round 926 (Div. 2)(A~C)

A. Sasha and the Beautiful Array 分析&#xff1a;说实话&#xff0c;打比赛的时候看到这题没多想&#xff0c;过了一下样例发现将数组排序一下就行&#xff0c;交了就过了。刚刚写题解反应过来&#xff0c;a2-a1a3-a2.....an-a(n-1) an - a1&#xff0c;所以最后结果只取决…

35岁转行,是我人生中最正确的选择

前言 经常听到有人说&#xff0c;35岁是职场的分水岭&#xff0c;但我觉得我的35岁&#xff0c;人生才刚刚开始。 35岁前后&#xff0c;我生二胎&#xff0c;考研&#xff0c;跳槽&#xff0c;转行&#xff0c;从传统行业到服务业&#xff0c;从服务业到新能源行业&#xff0…

第7讲 SpringSecurity执行原理概述

SpringSecurity执行原理概述 spring security的简单原理&#xff1a; SpringSecurity有很多很多的拦截器&#xff0c;在执行流程里面主要有两个核心的拦截器 1&#xff0c;登陆验证拦截器AuthenticationProcessingFilter 2&#xff0c;资源管理拦截器AbstractSecurityInterc…

问题:在解决思想认识上存在的问题讲解过程中和大家分享谁的一段原话() #其他#媒体

问题&#xff1a;在解决思想认识上存在的问题讲解过程中和大家分享谁的一段原话&#xff08;&#xff09; A&#xff0e;鲁迅 B&#xff0e;稻盛和夫 C&#xff0e;戴尔卡耐基 D&#xff0e;奥格曼狄诺 参考答案如图所示

应急响应实战笔记02日志分析篇(3)

第3篇:Web日志分析 ox01 Web日志 Web访问日志记录了Web服务器接收处理请求及运行时错误等各种原始信息。通过对WEB日志进行的安全分析&#xff0c;不仅可以帮助我们定位攻击者&#xff0c;还可以帮助我们还原攻击路径&#xff0c;找到网站存在的安全漏洞并进行修复。 我们来…

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

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

java8并行数据处理与性能

块并用不同的线程分别处理每个数据块的流。这样一来&#xff0c;你就可以自动把给定操作的工作负荷分配给多核处理器的所有内核,让它们都忙起来。让我们用一个简单的例子来试验一下这个思想。假设你需要写一个方法&#xff0c;接受数字n作为参数&#xff0c;并返回从1到给定参数…

Web APIs -05

js执行机制 js是单线程&#xff0c;同一个时间只能做一件事情&#xff0c;所有任务需要排队所以有时候会渲染不连贯 同步任务 都在主线程上执行&#xff0c;形成一个执行栈 异步任务 js的异步是通过回调函数实现的分为三类&#xff1a;1.普通事件&#xff1a;click等&…

基于Python实现Midjourney集成到(个人/公司)平台中

目前Midjourney没有对外开放Api&#xff0c;想体验他们的服务只能在discord中进入他们的频道进行体验或者把他们的机器人拉入自己创建的服务器中&#xff1b;而且现在免费的也用不了了&#xff0c;想使用就得订阅。本教程使用midjourney-api这个开源项目&#xff0c;搭建Midjou…

【并发编程】AQS原理

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳中求进&#xff0c;晒太阳 1. 概述 全称是 AbstractQueuedSynchronizer&#xff0c;是阻塞式锁和相关的同步器工具的框架 特点&#xff1a; 用 state 属性来表示资源的状…