[Linux]互斥锁(什么是锁,为什么需要锁,怎么使用锁(接口),演示代码)

目录

一、锁的概念

一些需要了解的概念

什么是锁?为什么需要锁?什么时候使用锁?怎么定义锁?

二、锁的接口

1.初始化锁

2.加锁

3.申请锁

4.解锁

5.销毁锁

三、实践(写代码):黄牛抢票


一、锁的概念

一些需要了解的概念

  • 临界资源:任一时刻只允许一个线程访问的共享资源
  • 临界区:访问临界资源的代码
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态:要么完成,要么未完成
  • 互斥:任何时刻,互斥可以保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用,而锁就是实现互斥的。
  • 同步:同步是一种机制,用于协调不同进程、线程或设备之间的操作,确保它们按照预期的顺序和方式进行。同步的目的是保持数据的一致性和系统的稳定性。

什么是锁?为什么需要锁?什么时候使用锁?怎么定义锁?

什么是锁?

锁是一种同步机制,用于控制多个线程对共享资源的访问。通过锁,可以确保一次只有一个线程能够访问特定的代码段或数据,从而防止数据竞争和不一致。锁的主要目的是确保数据的一致性和线程安全性。

为什么需要锁?

需要锁的主要原因在于确保多线程或多用户环境中共享资源访问的原子性和数据一致性。在多线程应用中,若多个线程同时访问并修改同一资源,可能导致数据冲突、不一致甚至损坏。

故事说明:把线程比作一个学生,小明,锁是自习室的门口上的锁头,当小明要进自习室时,他就从墙上拿钥匙(钥匙只有一把)解锁进入教室,而此时的自习室就是临界区,小明在自习室的书本,本子,笔就是临界资源,当小明突然要上厕所离开自习室时,因为自习室里有小明的书本呀,笔呀,等等东西,所以小明离开时就把门锁上了。小明自习了一天了,到晚上了吃饭了,小明不想自习了,小明带上他的东西离开,然后 把门锁上,把钥匙挂回墙上,此时其他同学就可以使用自习室了。在这例子中锁的作用就是只允许有钥匙的学生进入自习室,不允许其他没有钥匙的同学进入(其他线程),换言之锁的作用就是实现在一个临界区中的任一时刻只允许一个线程进入,访问。在这个故事中如果自习室门上没有锁,当小明要上厕所时,别的同学可以可以进入自习室破坏,拿走小明的东西呢?答案是有可能的,所以为了保证自习室里的小明的资源的安全,所以需要锁,把门上锁。

什么时候使用锁?

使用锁主要在多线程或多用户环境中,当多个线程或用户需要并发访问和修改共享资源时。锁能确保同一时间只有一个线程或用户访问资源,避免数据冲突和不一致。在需要保证数据完整性、原子性和安全性的场景下,应使用锁来同步和控制对共享资源的访问。

在Linux中锁长什么样呢?我们怎么定义锁呢?

pthread_mutex_t是一个用于线程同步的互斥锁类型。例如:pthread_mutex_t mutex:定义互斥锁变量mutex,mutex就是一个锁(锁变量)。

二、锁的接口

1.初始化锁

功能:用于初始化锁变量
原型

#include <pthread.h>

锁为局部变量时使用如下函数初始化

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);

锁为全局变量时使用如下方法初始化

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 

参数

  1. pthread_mutex_t *restrict mutex:指向要初始化的互斥锁变量的指针。这个指针指向的互斥锁变量在调用 pthread_mutex_init 之前应该是未初始化的。

  2. const pthread_mutexattr_t *restrict attr:指向互斥锁属性的指针。这个参数是可选的,通常可以传递 NULL (nullptr)来使用默认的互斥锁属性。如果你需要设置特定的属性(例如互斥锁的类型),你需要先使用 pthread_mutexattr_init 初始化一个 pthread_mutexattr_t 变量,然后设置所需的属性,最后将其传递给 pthread_mutex_init

返回值:成功返回0;失败返回错误码

使用例子:

#include <iosteam>
#include <pthread.h>
using namespace std;//全局锁初始化方式
pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;//定义并初始化锁int main()
{//局部初始化方式pthread_mutex_t local_mutex;//定义锁pthread_mutex_init(&local_mutex, nullptr);//初始化锁//加锁//...//解锁//销毁锁return 0;
}

2.加锁

功能:获取(锁定)互斥锁,如果锁当前未被其他线程占用(即锁是“空闲”的),那么调用此函数的线程将成功获取锁,并可以继续执行其临界区代码。如果锁已被其他线程占用,则调用线程将被阻塞,直到锁被释放(即被当前持有锁的线程调用 pthread_mutex_unlock
原型

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t *mutex);

参数

pthread_mutex_t *mutex:是一个指向互斥锁变量的指针。

返回值

pthread_mutex_lock 函数的返回值用于指示加锁操作是否成功。

  • 如果成功获取锁,函数返回 0
  • 如果在尝试获取锁时发生错误(例如,由于无效的互斥锁指针或系统资源不足),函数将返回一个错误码(非零值)。具体的错误码可以根据不同的系统和库实现而有所不同,但通常会遵循 POSIX 线程标准中定义的错误码。

注意事项

  • 使用 pthread_mutex_lock 时,必须确保在不再需要锁时调用 pthread_mutex_unlock 来释放锁,以避免死锁。
  • 如果在调用 pthread_mutex_lock 后线程被中断或取消,锁可能仍然处于锁定状态,需要特别小心处理。
  • 如果互斥锁的类型是递归锁(recursive mutex),则同一个线程可以多次获取同一个锁,但每次获取锁后都必须对应地释放锁。

3.申请锁

功能:尝试获取一个互斥锁(mutex),而不会阻塞调用线程。如果互斥锁已经被其他线程持有,则 pthread_mutex_trylock 不会使调用线程进入睡眠状态等待锁释放,而是立即返回表示失败的错误码。
原型

#include <pthread.h>

int pthread_mutex_trylock(pthread_mutex_t *mutex);
参数

pthread_mutex_t *mutex:是一个指向互斥锁变量的指针。
返回值

  • 如果成功获取锁,函数返回 0
  • 如果锁已被其他线程占用,或者发生其他错误(如传递了无效的互斥锁指针),函数将返回一个错误码。常见的错误码包括 EBUSY(表示锁当前被其他线程占用)和 EINVAL(表示传递给函数的互斥锁是无效的)。

4.解锁

功能:用于释放互斥锁(mutex),在多线程编程中用于确保线程同步的正确性。当一个线程完成对共享资源的访问后,它应该调用 pthread_mutex_unlock 来释放锁,以便其他线程能够获取该锁并访问相同的资源。
原型

#include <pthread.h>

int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数

pthread_mutex_t *mutex:是一个指向互斥锁变量的指针。
返回值

  • 如果成功释放锁,函数返回 0
  • 如果在尝试解锁时发生错误(例如,传递给函数的互斥锁是无效的,或者当前线程没有持有该锁),函数将返回一个错误码。常见的错误码包括 EINVAL(表示传递给函数的互斥锁是无效的)和 EPERM(表示当前线程没有持有该锁)。

5.销毁锁

功能:用于销毁(释放)互斥锁(mutex)的函数。在多线程编程中,当不再需要某个互斥锁时,应该调用 pthread_mutex_destroy 来销毁它,以释放相关资源。
原型

#include <pthread.h>

int pthread_mutex_destroy(pthread_mutex_t *mutex);

参数

pthread_mutex_t *mutex:是一个指向互斥锁变量的指针。
返回值

  • 如果成功销毁锁,函数返回 0
  • 如果在尝试销毁锁时发生错误(例如,传递给函数的互斥锁是无效的,或者锁仍被持有),函数将返回一个错误码。常见的错误码包括 EBUSY(表示锁当前被其他线程占用)和 EINVAL(表示传递给函数的互斥锁是无效的)。

三、实践(写代码):黄牛抢票

说明:用多线程模拟黄牛,常数模拟票

Makefile

test:test.ccg++ -o $@ $^ -std=c++11 -lpthread
PHONY:clean
clean:rm -f test;

test.cc

#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <vector>
using namespace std;
int ticket = 1000; // 一千张票
int threadnum = 5; // 黄牛数
// 定义全局锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *threadtask(void *args)
{while (ticket > 0){string name = static_cast<char *>(args);// 加锁pthread_mutex_lock(&mutex);cout << "我是: " << name << "我抢到了" << ticket << "号票" << endl;ticket--; // 票数--sleep(1);// 解锁pthread_mutex_unlock(&mutex);}return nullptr;
}
int main()
{// 五个黄牛vector<pthread_t> threads;for (int i = 0; i < threadnum; i++){pthread_t tid;char threadname[64];sprintf(threadname, "thraed-%d", i + 1);pthread_create(&tid, nullptr, threadtask, threadname);threads.push_back(tid);}void *ret;for (int i = 0; i < threads.size(); i++){pthread_join(threads[i], &ret);//等待线程,回收资源}// 销毁锁pthread_mutex_destroy(&mutex);return 0;
}

结果

全是5号线程抢到票,原因是Linux内核中的线程调度器根据线程的优先级、状态和其他因素来决定哪个线程应该被调度执行。如果某个线程的优先级高于其他线程,或者其状态更适合执行(例如,它已准备好运行并且没有受到阻塞),那么它就更有可能被调度器选中。你可以在你的linux中试试或许会有不同的结果。

0c1a3fe630b84286af006feae9802cef.png

 完结!!!

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

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

相关文章

华曦传媒陆锋:数字媒体时代,社区电梯广告价值正在被重估

在数字化时代的浪潮中&#xff0c;电梯广告、停车场道闸广告、门禁灯箱广告等线下社区广告似乎面临着生存的挑战。 然而&#xff0c;这一传统广告形式展现出了惊人的韧性和价值。 比如&#xff0c;2023年上半年&#xff0c;作为行业龙头分众传媒&#xff0c;2023年上半年实现…

GraalVM详细安装及打包springboot、java、javafx使用教程(环境安装篇)

下一篇:GraalVM详细安装及打包springboot、java、javafx使用教程(打包普通JAVA项目篇) GraalVM介绍 GraalVM是一款由Oracle公司开发的一款具有高效性能、降低基础设施成本、支持Java发展、与其他编程语言无缝集成、创建本机镜像等优点的跨平台虚拟机。它支持多种编程语言&…

Nacos详解,从安装到服务部署,及nginx反向代理

Nacos 安装 Windows安装 下载 在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; GitHub主页&#xff1a;https://github.com/alibaba/nacos GitHub的Release下载页&#xff1a;https://github.com/alibaba/nacos…

Python 安装目录及虚拟环境详解

Python 安装目录 原文链接&#xff1a;https://blog.csdn.net/xhyue_0209/article/details/106661191 Python 虚拟环境 python 虚拟环境图解 python 虚拟环境配置与详情 原文链接&#xff1a;https://www.cnblogs.com/hhaostudy/p/17321646.html

下沉市场会给蔚来带来新“未来”吗?

2023年以来&#xff0c;在价格战、技术战等多重因素的催化下&#xff0c;我国汽车行业的洗牌在持续进行。一边是小米等手机厂商跨界入场&#xff0c;一边是三菱等合资品牌淡出大众视野。市场格局正在重塑。 这种情况下&#xff0c;现有车企的一举一动都备受市场关注。其中&…

09 事务和连接池

文章目录 properties文件连接池service层实现类dao层实现类dao层实现类 连接池类: 创建线程池静态常量&#xff0c;用于放连接。 创建Properties静态常量&#xff0c;用于解析properties文件 静态代码块中&#xff0c;解析properties文件&#xff0c;将解析结果用于创建连接池 …

手写一个跳表,跪了。。。

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格&#xff0c;遇到很多很重要的相关面试题&#xff1a; 手写一个跳表&#xff1f; redis为什…

技能篇:如何批量替换文件名称 一招批量替换文件名

在日常生活和工作中&#xff0c;我们经常需要处理大量的文件&#xff0c;而文件名的设置对于文件的管理和查找至关重要。一个清晰、有序的文件名能够帮助我们快速找到所需的文件&#xff0c;提高工作效率。然而&#xff0c;随着时间的推移和项目的增多&#xff0c;我们可能需要…

【JS】JavaScript 中的原型与原型链

JavaScript 中的原型与原型链 原型1 函数中 prototype 指向原型对象2 对象中 __proto__ 指向原型对象3 原型对象中 constructor 指向构造函数4 __proto__ 与 [[Prototype]] 的关系5 所有非空类型数据&#xff0c;都具有原型对象6 new运算符做了哪些事情 原型链1 举个栗子1.1 直…

使用有道bce-embedding-vase-v1模型构建知识向量库并进行相似度搜索

国产embedding 最开始使用LangChain结合通义千问API实现了基础的RAG&#xff08;Retrieval-Augmented Generation&#xff09;过程&#xff0c;当时认为embedding模型似乎是LangChain的一部分&#xff0c;然后又通过学习OpenAI的API发现&#xff0c;其实使用embedding模型不需要…

智能农业:农业技术与效益

文章目录 什么是智慧农业&#xff1f;智能农业的好处智能农业技术物联网智能农业解决方案智能农业软件和移动应用程序智能农业的挑战作物监测卫星智能农业解决方案使用卫星数据数据测量历史数据和预测在便携式设备上使用应用程序 智能农业的未来参考 现代技术的发展影响着人类活…

走进jvm之垃圾回收器篇

这里我想首先说明一下&#xff0c;虽然我们经常会拿垃圾回收器来做比较&#xff0c;虽然想挑选一个最好的收集器出来&#xff0c;但是目前也没有说哪一款收集器是完美的&#xff0c;更不存在万能的收集器&#xff0c;我们也只是对收集器选择最适合场景的一个收集器。 那么作者将…

深入解析权限之钥RBAC模型!

在2B系统中设计中&#xff0c;角色基于访问控制&#xff08;RBAC&#xff0c;Role-Based Access Control&#xff09;是最常见的权限管理模型之一。它将权限分配给角色而非个别用户&#xff0c;简化了权限管理的过程。接下来我们一起了解下几种常见的RBAC模型。 1. 标准 RBAC&…

母亲的奶牛(蓝桥杯,acwing每日一题)

题目描述&#xff1a; 农夫约翰有三个容量分别为 A,B,C升的挤奶桶。 最开始桶 A 和桶 B 都是空的&#xff0c;而桶 C 里装满了牛奶。 有时&#xff0c;约翰会将牛奶从一个桶倒到另一个桶中&#xff0c;直到被倒入牛奶的桶满了或者倒出牛奶的桶空了为止。 这一过程中间不能有…

每日学习笔记:C++ STL 的无序容器(unordered_set、unordered_map)

定义 特性 能够快速查找元素 操作函数 负载系数 元素个数 / bucket个数 提供哈希函数 提供等价准则 方法一&#xff1a;重写元素的操作符 方法二&#xff1a;自定义函数对象 提供自定义哈希函数和等价准则例子 例一&#xff1a;传入函数对象 例二&#xff1a;传入lambda 检…

蓝桥杯2023省赛:矩阵总面积|模拟、数学(几何)

题目链接&#xff1a; 0矩形总面积 - 蓝桥云课 (lanqiao.cn) 说明&#xff1a; 参考文章&#xff1a;矩形总面积计算器&#xff1a;计算两个矩形的总面积&#xff0c;包括重叠区域_矩形r1的左下角坐标为x1, yl 、宽度为w1、高度为h1, 矩形r2的左下角坐标为x2,y2、宽-CSDN博客…

移卡 2023 年支付GPV超 2.88 万亿 龙头地位稳固

3月21日&#xff0c;中国领先的基于支付的科技平台——移卡有限公司&#xff08;以下简称“移卡”或“公司”&#xff0c;股份代号&#xff1a;09923.HK&#xff09;发布2023年年度业绩报告。与上年同期相比&#xff0c;移卡2023年收入同比增长15.6%&#xff0c;至人民币39.51亿…

Java代码基础算法练习-求一个三位数的各位平方之和-2024.03.21

任务描述&#xff1a; 输入一个正整数n&#xff08;取值范围&#xff1a;100<n<1000&#xff09;&#xff0c;然后输出每位数字的平方和。 任务要求&#xff1a; 代码示例&#xff1a; package march0317_0331;import java.util.Scanner;public class m240321 {public …

YOLOV5 改进:替换backbone为Swin Transformer

1、前言 本文会将YOLOV5 backbone更换成Swin Transformer 具体为什么这样实现参考上文:YOLOV5 改进:替换backbone(MobileNet为例)-CSDN博客 这里只贴加入的代码 训练结果如下: 2、common文件更改 在common文件中加入下面代码: 这里是swin transformer的实现,参考:…

如何申请免费通配符SSL证书

步骤1&#xff1a;了解免费通配符证书的选项 首先&#xff0c;您需要了解哪些机构或项目提供免费的通配符证书。目前绝大部分CA机构只提供免费的单域名证书&#xff0c;只有少数服务商提供商可以提供免费的通配符证书&#xff0c;比如JoySSL。 免费通配符证书申请地址https://…