Linux线程 -- 互斥锁 和 条件变量

在多线程编程中,互斥量(mutex)是用于保护共享资源的同步机制,确保在任一时刻只有一个线程能够访问共享资源。互斥量用于防止竞态条件(race conditions),确保数据一致性。

基本概念

互斥量(mutex)是一种锁机制,用于实现线程之间的互斥访问。它有两个基本操作:

  1. 锁定(lock):一个线程锁定互斥量以获得对共享资源的独占访问权。如果互斥量已经被其他线程锁定,调用该操作的线程会被阻塞,直到互斥量被解锁。
  2. 解锁(unlock):一个线程解锁互斥量,释放对共享资源的独占访问权,从而允许其他被阻塞的线程获得该资源的访问权。

在Linux中使用互斥量

在Linux中,可以使用POSIX线程库(pthread)中的互斥量。下面是一些主要函数:

  1. 初始化互斥量
    • pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
  2. 销毁互斥量
    • pthread_mutex_destroy(pthread_mutex_t *mutex);
  3. 锁定互斥量
    • pthread_mutex_lock(pthread_mutex_t *mutex);
    • pthread_mutex_trylock(pthread_mutex_t *mutex);
    • pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout);
  4. 解锁互斥量
    • pthread_mutex_unlock(pthread_mutex_t *mutex);

示例代码

以下是一个使用互斥量保护共享资源的简单示例:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 互斥锁的声明
pthread_mutex_t mutex;// 共享变量
int i = 0;// 线程函数1
void *func1(void *arg)
{static char *p = "t1 is run";pthread_mutex_lock(&mutex);  // 获取互斥锁for(i = 0; i < 5; i++) {printf("func1: %d\n", i);sleep(1);}printf("func1: i = %d\n", i);pthread_mutex_unlock(&mutex);  // 释放互斥锁pthread_exit((void *)p);  // 退出线程并返回信息
}void *func2(void *arg)
{static char *p = "t2 is run";while(1){if(i == 5){pthread_mutex_lock(&mutex);  // 获取互斥锁printf("fun2: I got mutex\n");printf("fun2=========: %d\n", i);pthread_mutex_unlock(&mutex);  // 释放互斥锁pthread_exit((void *)p);  // 退出线程并返回信息}}
}int main()
{int param = 100;pthread_t t1;pthread_t t2;// 初始化互斥锁pthread_mutex_init(&mutex, NULL);char *pret = NULL;char *pret2 = NULL;// 创建线程1int ret = pthread_create(&t1, NULL, func1, (void *)&param);if(ret == 0){printf("successfully creat a pthread1!\n");}else{printf("faild to creat a pthread\n");}// 创建线程2int ret2 = pthread_create(&t2, NULL, func2, (void *)&param);if(ret2 == 0){printf("successfully creat a pthread2!\n");}else{printf("faild to creat a pthread\n");}printf("I am main: %ld\n", (unsigned long)pthread_self());// 等待线程1和2结束pthread_join(t1, (void **)&pret);pthread_join(t2, (void **)&pret2);printf("main: t1 quit: %s\n", pret);printf("main: t2 quit: %s\n", pret2);// 销毁互斥锁pthread_mutex_destroy(&mutex);return 0;
}

运行结果:

解释

  1. 定义互斥量:使用 pthread_mutex_t 类型定义一个互斥量变量 mutex
  2. 初始化互斥量:在使用互斥量之前,需要调用 pthread_mutex_init 函数初始化互斥量。
  3. 锁定和解锁互斥量:在访问共享资源时,使用 pthread_mutex_lockpthread_mutex_unlock 函数锁定和解锁互斥量,确保每次只有一个线程能够访问共享资源。
  4. 销毁互斥量:在不再需要互斥量时,调用 pthread_mutex_destroy 函数销毁互斥量。

注意事项

  1. 避免死锁:确保每个锁定的互斥量最终会被解锁,避免死锁情况的发生。
  2. 正确初始化和销毁:在使用互斥量前一定要初始化,使用后要销毁。
  3. 最小锁定范围:尽量减少锁定的范围,只在必要的代码段中使用锁,以提高并发性。

通过正确使用互斥量,可以确保多线程程序中的共享资源被安全地访问和修改,防止竞态条件的发生。

问题1:什么情况会造成死锁?

在Linux系统中,互斥锁(mutex)用于确保多个线程不会同时访问共享资源。然而,不正确的使用互斥锁可能会导致死锁。最常见的情况如下:

相互持有资源且等待对方释放

这是最经典的死锁场景,通常被称为“循环等待”条件。假设有两个线程,分别持有锁A和锁B:

  • 线程1持有锁A,等待锁B。
  • 线程2持有锁B,等待锁A。

这种情况下,两个线程会无限期地等待对方释放锁,导致死锁。

条件变量

         条件变量(condition variable)是用于线程间协调的一种同步机制。它允许线程在特定条件不满足时等待,并在条件满足时收到通知继续执行。条件变量通常与互斥锁(mutex)结合使用,以确保对共享资源的访问是安全的。

条件变量的主要操作

  1. 初始化和销毁

    • pthread_cond_init: 初始化条件变量。
    • pthread_cond_destroy: 销毁条件变量。
  2. 等待和唤醒

    • pthread_cond_wait: 释放互斥锁并等待条件变量,直到收到信号。
    • pthread_cond_signal: 唤醒一个等待该条件变量的线程。
    • pthread_cond_broadcast: 唤醒所有等待该条件变量的线程。

使用条件变量的步骤

  1. 初始化条件变量和互斥锁
  2. 在条件不满足时等待
  3. 在条件满足时唤醒等待线程
  4. 销毁条件变量和互斥锁

相关函数介绍 

1. pthread_cond_init

功能

初始化条件变量。

原型
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
参数
  • cond: 指向需要初始化的条件变量的指针。
  • attr: 条件变量属性,如果为NULL,使用默认属性。
返回值
  • 成功返回0。
  • 失败返回错误码。

 示例

pthread_cond_t cond;
pthread_cond_init(&cond, NULL);

2. pthread_cond_destroy

功能

销毁条件变量。

原型
int pthread_cond_destroy(pthread_cond_t *cond);
参数
  • cond: 指向需要销毁的条件变量的指针。
返回值
  • 成功返回0。
  • 失败返回错误码。
示例
pthread_cond_destroy(&cond);

3. pthread_cond_wait

功能

等待条件变量。在等待期间,会释放与条件变量关联的互斥锁,并在收到信号后重新获得锁。

原型
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数
  • cond: 指向条件变量的指针。
  • mutex: 指向与条件变量关联的互斥锁的指针。
返回值
  • 成功返回0。
  • 失败返回错误码。

示例 

pthread_mutex_lock(&mutex);
while (condition_is_not_met) {pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);

4. pthread_cond_signal

功能

发送信号给一个等待该条件变量的线程,唤醒它。

原型
int pthread_cond_signal(pthread_cond_t *cond);
参数
  • cond: 指向条件变量的指针。

示例 

pthread_mutex_lock(&mutex);
condition_is_met = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
返回值
  • 成功返回0。
  • 失败返回错误码。

5. pthread_cond_broadcast

功能

发送信号给所有等待该条件变量的线程,唤醒它们。

原型
int pthread_cond_broadcast(pthread_cond_t *cond);
参数
  • cond: 指向条件变量的指针。
返回值
  • 成功返回0。
  • 失败返回错误码。
示例
pthread_mutex_lock(&mutex);
condition_is_met = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);

条件变量使用示例

以下是一个示例程序,展示了如何使用条件变量和互斥锁同步两个线程的操作:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 定义互斥锁和条件变量
pthread_mutex_t mutex;
pthread_cond_t cond;
int i = 0; // 共享资源// 线程函数1
void *func1(void *arg) {pthread_mutex_lock(&mutex);  // 加锁保护共享资源for (i = 0; i < 5; i++) {printf("func1: %d\n", i);sleep(1);  // 模拟工作}pthread_cond_signal(&cond);  // 通知等待线程条件已满足pthread_mutex_unlock(&mutex);  // 释放锁pthread_exit(NULL);  // 退出线程
}// 线程函数2
void *func2(void *arg) {pthread_mutex_lock(&mutex);  // 加锁保护共享资源while (i < 5) {  // 当条件不满足时等待pthread_cond_wait(&cond, &mutex);  // 等待条件变量的信号}printf("func2: %d\n", i);pthread_mutex_unlock(&mutex);  // 释放锁pthread_exit(NULL);  // 退出线程
}int main() {pthread_t t1, t2;// 初始化互斥锁和条件变量pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond, NULL);// 创建线程1和线程2pthread_create(&t1, NULL, func1, NULL);pthread_create(&t2, NULL, func2, NULL);// 等待线程1和线程2结束pthread_join(t1, NULL);pthread_join(t2, NULL);// 销毁互斥锁和条件变量pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

运行结果如下: 

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

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

相关文章

python学习笔记-04

高级数据类型 一组按照顺序排列的值称为序列&#xff0c;python中存在三种内置的序列类型&#xff1a;字符串、列表和元组。序列可以支持索引和切片的操作&#xff0c;第一个索引值为0表示从左向右找&#xff0c;第一个索引值为负数表示从右找。 1.字符串操作 1.1 切片 切片…

不同平台账号究竟要如何运营?新媒体矩阵这样做,不怕没结果!

干货分享 越来越多企业要求做矩阵化运营&#xff0c;众多平台一把抓&#xff0c;那么对于新媒体人来说&#xff0c;可能会有些困惑&#xff0c;都是新媒体平台&#xff0c;他们各有什么特质&#xff1f;今天冲鸭老师就对目前新媒体4大热榜平台进行分析。 抖音 用户特点 年轻…

Flutter 中的 ErrorWidget 小部件:全面指南

Flutter 中的 ErrorWidget 小部件&#xff1a;全面指南 Flutter 是一个由 Google 开发的跨平台 UI 框架&#xff0c;它允许开发者使用 Dart 语言构建高性能、美观的应用。在 Flutter 的丰富组件库中&#xff0c;ErrorWidget 是一个特殊的组件&#xff0c;用于在渲染过程中捕获…

Unity 编辑器扩展 一键替换指定物体下的所有材质球

先看效果 实现方案 1&#xff1a;创建几个用于测试的Cube 2&#xff1a;创建一个脚本 3:编写脚本内容 主要是这部分的逻辑 附上完整代码 using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine;public class Tool {[MenuItem(…

json文件操作和异常处理

目录 按行读取文件readline() 读取大文件: json文件: json文件介绍: json的语法&#xff1a; 读取json文件: json文件写入: 异常&#xff1a; 捕获异常: 捕获指定类型的异常: 捕获未知类型的异常(使用最多): 异常捕获的完整结构: 异常传递: ​编辑抛出异常: 按行…

[HDCTF 2023]Normal_Rsa(e,phi不互素)

题目&#xff1a; from Crypto.Util.number import * mbytes_to_long(bxxxxxx) pgetPrime(256) qgetPrime(256) e74 np*q cpow(m,e,n) print("p",p) print("q",q) print("c",c) #p 8605358291738634342256717476404047103323438810696848883487…

如何评价GPT-4o?【模板】

如何评价GPT-4o? 简介&#xff1a;最近&#xff0c;GPT-4o横空出世。对GPT-4o这一人工智能技术进行评价&#xff0c;包括版本间的对比分析、GPT-4o的技术能力以及个人感受等。 提醒&#xff1a;在发布作品前&#xff0c;请把不需要的内容删掉。 方向一&#xff1a;对比分析 提…

C++字符串转base64编码

上一篇博客中分享的案例里面base64编码的工具函数单独拿出来分享一下&#xff0c;为不想自己写的大佬提供快捷的CV路径 const std::string base64_chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz""0123456789/";std::string ba…

java如何通过循环计算阶乘

比如说要计算5的阶乘 先定义一个变量a5 再定义一个变量b1 通过一个循环 b*a a-- 示例代码如下 public class HelloWorld { public static void main(String[] args) { int a5; int b1; do { b*a; a--; } while(a>0); System.out.println(b); } }

openAI项目

文章目录 为什么单独提供chatgpt-sdk&#xff1f; 分而治之&#xff0c;不同的模块修改&#xff0c;不会影响到整体的变动。比如就只是 sdk 调整&#xff0c;或者再引入新的 sdk 都会非常容易管理。资源问题&#xff0c;如果公司内有多个系统都需要用到这个 sdk&#xff0c;那么…

A6500-LC LVDT 前置器,用于A6500-UM, 导轨安装

电源 22.5V to 32VDC <30mA <0.1%/V <60V( 使用SELV/PELV 供电电源) 约2.2Vrms,5kHz IP20 IEC 60529 -35C to 75C(-31F to 167F) -35C to 85C(-31F to 185F) 电流损耗 供电电压对 运行温度 存储温度 0.35mm(0.014 in ),10 to 55Hz 15g 根据 EN 60068-2-27 根据IEC 613…

北邮21硕后端开发笔记

blog 整理北邮21渣硕Java后端开发知识网络&#xff0c;阅读笔记以及技术博客&#xff0c;持续更新&#xff01;欢迎Star&#xff01; GitHub: https://github.com/WeiXiao-Hyy/blog Java 基础篇 一文带你搞懂final关键字 Java并发编程 fucking-java-concurrency解读 CS…

linux必学基础命令大全

一切皆文件&#xff0c;每个文件都有具体的用途 命令快捷查看目录 常用命令 - 目录类1、ls 查看当前目录下的文件2、man查看命令详细信息3、pwd 查看当前目录 -4、cd 进入目录5、清屏命令6、mkdir创建目录7、du查看文件或者文件夹大小 常用命令 - 文件类1、vim/vi使用2、cat 查…

Maven实战: 从工程创建自定义archetype

在上一节中(创建自定义archetype)我们手动创建了一个项目模板&#xff0c;经过5步能创建出一个项目模板&#xff0c;如果我有一个现成的项目&#xff0c;想用这个项目作为模板来生成其他项目呢&#xff1f;Maven提供了基于项目生成archetype模板的能力&#xff0c;我们分3步来讲…

Windows下 CLion中,配置 OpenCV、LibTorch

首先按照win下C部署深度学习模型之clion配置pytorchopencv教程记录 步骤配置。 LibTorch 部分 在测试LibTorch时会出现类似 c10.dll not found 的问题&#xff08;Debug才有&#xff09;&#xff1a; 参考C部署Pytorch&#xff08;Libtorch&#xff09;出现问题、错误汇总和 …

行业分析---造车新势力之理想汽车

1 前言 在之前的博客中&#xff0c;笔者撰写了多篇行业类分析的文章&#xff08;科技新能源&#xff09;&#xff1a; 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 此类文章的受…

js - WebWorkers

多线程: Web Workers 允许你创建一个或多个独立的线程来运行JavaScript&#xff0c;这些线程与主执行线程&#xff08;UI线程&#xff09;分离。 不阻塞UI: 因为脚本在单独的线程中运行&#xff0c;所以即使它们需要很长时间来执行&#xff0c;也不会阻塞用户界面或影响用户交…

vulntarget-b记录(Sliver学习)

网络环境 域控&#xff08;Win2016&#xff09; vulntarget\administrator&#xff1a;Admin123、&#xff08;首次登陆要改密码修改为Admin123&#xff09; vulntarget\win101&#xff1a;admin#123 边界Web主机突破 nmap扫描发现81端口 通过扫描&#xff0c;fuzz出来了后…

【Python学习】面向对象(OOP)

让我们从Python面向对象编程&#xff08;OOP&#xff09;的基础概念开始&#xff0c;逐步深入到继承、多态、特殊方法和运算符重载。 一、类和对象 什么是类和对象&#xff1f; - 类&#xff08;Class&#xff09;&#xff1a;类是创建对象的蓝图或模板。它定义了一组属性和方法…

c语言如何改变文件读取位置

c语言要改变文件读取位置&#xff0c;会用到rewind语句和fseek语句 rewind语法格式是 rewind(fp)将fp指向的文件读写指针重新指向文件开头 rewind代码示例如下 #include<stdio.h> int main() {FILE *fp1,*fp2;char buf[10];int a;fp1fopen("aaa.txt","…