Linux系统编程之线程互斥锁的使用方法

文章目录

  • 一、Linux上线程开发互斥锁概要
  • 二、创建及销毁互斥锁
    • 2.1 示例:主线程等待两个线程退出,1线程和2线程打印信息
  • 三、互斥量的初始化问题

一、Linux上线程开发互斥锁概要

互斥量(mutex)从本质上来说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后,释放互斥量上的锁。 对互斥量进行加锁后,任何其它试图在再次对互斥量加锁的进行会被阻塞直到当前线程释放该互斥量上的锁。如果释放互斥锁时,有多个线程阻塞,则所有在该互斥锁的线程都会变成可运行状态,第一个变成可运行状态的线程可以对互斥量加锁,其它线程将会看到互斥锁依然被锁住,只能等待它从新变成可用。在这种方式下,每次只有一个线程可以向前运行。

在设计时需要规定所有的线程必须遵守相同的数据访问原则。只有这样,互斥机制才能正常工作。操作系统并不会做数据访问的串行化。如果允许其中的某个线程在没有得到锁的情况下也可以访问共享资源,那么即使其它的线程在使用共享资源前都获取了锁,也还是会出现数据不一致的问题。

互斥量变量使用 pthread_mutex_t 的数据类型表示。在使用互斥变量前必须对它进行初始化,可以把它置为常量 PTHREAD_MUTEX_INITALIZER(只对静态分配的互斥量),也可以通过调用 pthread_mutex_init 函数进行初始化。如果动态地分配互斥量(比如通过调用malloc函数),那么在释放内存前需要调用 pthread_mutex_destroy

二、创建及销毁互斥锁

对锁的操作

#include <pthread.h>
// 动态初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
// 销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号

2.1 示例:主线程等待两个线程退出,1线程和2线程打印信息

不加锁的程序:

//demo5
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int g_data=0;

void* fun1(void *arg)
{
        printf("t1:%ld thread is create\n", (unsigned long)pthread_self());
        printf("t1: %d\n", *((int*)arg));
}

void* fun2(void *arg)
{
        printf("t2:%ld thread is create\n", (unsigned long)pthread_self());
        printf("t2: %d\n", *((int*)arg));
}

int main()
{

        //int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
        int ret;
        int param = 100;
        pthread_t t1;
        pthread_t t2;

        //                       线程属性 线程函数 线程函数参数
        ret = pthread_create(&t1, NULL, fun1, (void*)&param);
        if(ret == 0){
                printf("main:create t1 success\n");
        } else {
                perror("why t1 fail");
        }

        ret = pthread_create(&t2, NULL, fun2, (void*)&param);
        if(ret == 0){
                printf("main:create t1 success\n");
        } else {
                perror("why t2 fail");
        }

        printf("main:%ld\n", (unsigned long)pthread_self());//打印主线程ID


        pthread_join(t1, NULL);//等待线程结束,防止进程结束,线程还未执行完毕
        pthread_join(t2, NULL);//等待线程结束,防止进程结束,线程还未执行完毕

        return 0;
}

在这里插入图片描述
从运行结果看出:执行顺序不一样,每次都不是固定的顺序。

思考:那我们能不能让 t1先运行,t2运行,然后 main 最后运行?能不能保证能!得加钱!啊不,得加锁

想让t1先运行,需要先定义一个锁。被锁锁住的代码都叫做互斥量

加锁步骤:

  1. 创建一个锁,锁的名字叫做mutex,是一个全局变量,线程1和线程2都能看到这把锁。 在这里插入图片描述

  2. 在创建线程之前对锁进行初始化 在这里插入图片描述

  3. 程序退出后,要销毁这把锁
    在这里插入图片描述

  4. 想让t1先运行,对t1进行上锁:先上锁,打印两句话,然后解锁在这里插入图片描述

  5. 同理,t2也是在这里插入图片描述

运行结果:
编译 -> 运行 -> 结果:都是t1先执行(由于没加延时,可能存在偶然性,每次恰好是t1先执行完例程,因为计算机算力太强了,程序很小)
在这里插入图片描述

修改t1:让多执行几次(几百几千次也行,可以大一点,或者选择加延时函数),测试互斥锁。
在这里插入图片描述

运行结果:
在这里插入图片描述

互斥量就是一把锁,被锁锁住的代码都叫做互斥量。对锁操作有加锁操作 pthread_mutex_lock() 和解锁操作 pthread_mutex_unlock 。在加锁和解锁之间的代码,称之为共享资源。

可见,对于共享资源的使用,只有锁被释放后,其它依赖共享资源的线程才能得以继续执行。

三、互斥量的初始化问题

可以使用宏进行初始化,属于是静态初始化。

在使用互斥变量前必须进行初始化,可以置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量);也可以通过调用pthread_mutex_init、pthread_cond_init函数进行初始化。如果动态地分配互斥量,那么在释放内存前需要调用pthread_mutex_destroy。

动态初始化:
pthread_mutex_t mutex;
主函数中必须:
pthread_mutex_init(&mutex, NULL); //dynamic init

使用宏进行初始化(静态初始化):
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // static init

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小白水平理解面试经典题目leetcode 606. Construct String from Binary Tree【递归算法】

Leetcode 606. 从二叉树构造字符串 题目描述 例子 小白做题 坐在自习室正在准备刷题的小白看到这道题&#xff0c;想想自己那可是没少和白月光做题呢&#xff0c;也不知道小美刷题刷到哪里了&#xff0c;这题怎么还没来问我&#xff0c;难道是王谦谦去做题了&#xff1f; 这…

Dockerfile(6) - EXPOSE 指令详解

EXPOSE 通知 Docker 容器在运行时监听指定的网络端口 EXPOSE 端口号 EXPOSE 端口号/协议 默认协议是 TCP 同时在 TCP、UDP 上暴露端口 EXPOSE 80/tcp EXPOSE 80/udp EXPOSE 原理 个人理解&#xff1a;EXPOSE 暴露的端口更像是指明了该容器提供的服务需要用到的端口EXPOSE…

【比较mybatis、lazy、sqltoy、lambda、操作数据 】操作批量新增、分页查询

orm框架使用Lambda性能比较 环境&#xff1a; idea jdk17 spring boot 3.0.7 mysql 8.0测试条件常规对象 orm 框架是否支持xml是否支持 Lambda对比版本mybatis☑️☑️3.5.4sqltoy☑️☑️5.2.98lazy✖️☑️1.2.3-JDK17 数据库表(含有唯一性索引s_u) CREATE TABLE sys_u…

机器学习|线性回归

线性回归是尝试使用一条直线去拟合出图上的节点。 e i e_i ei​为第i个点构成的误差&#xff0c;使用平方的好处一是可以避免正负抵消&#xff0c;二是平方有利于放大大于1的误差的影响&#xff0c;同时缩小误差小于1的影响。 将平方项进行展开&#xff0c;以w作为变元&…

Floyd算法、Dijkstra算法、基础拓扑排序

Floyd算法 Dijkstra算法 基础拓扑排序

简单了解B树和B+树

目录 B树 B树 B树和B树的结构示意图 总结 B树和B树是两种非常重要的树状数据结构&#xff0c;它们广泛应用于数据库和文件系统的索引结构中。这两种数据结构能够帮助我们高效地管理、查询以及更新大量的数据。下面&#xff0c;我将简单介绍它们,以及他们之间的区别。 B树 B…

内存飙高问题如何排查?

目录 1、查看日志 2、查看GC情况 3、分析堆内存对象占用情况 4、分析堆内存快照文件 内存飙高如果发生在java进程上&#xff0c;一般情况是因为创建了大量对象导致&#xff0c;持续飙高说明垃圾回收跟不上对象创建的速度&#xff0c;或者内存泄漏导致对象无法被回收&#x…

unity学习(42)——创建(create)角色脚本(panel)——UserHandler(收)+CreateClick(发)——服务器收包2

1.解决上一次留下的问题&#xff1a; log和reg的时候也有session&#xff0c;输出看一下这两个session是同一个不&#xff1a; 实测结果reg log accOnline中的session都是同一个对象&#xff0c;但是getAccid时候的session就是另一个了。 测试结果&#xff0c;说明在LogicHan…

小程序中使用echarts地图

一、下载并安装echarts 1、下载echarts-for-weixin组件 echarts-for-weixin项目提供了一个小程序组件&#xff0c;用这种方式可以在小程序中方便地使用 ECharts。 下载ec-canvas项目&#xff08;下载地址&#xff09; ​​ 注意&#xff1a;下载的 ec-canvas 中的echarts的版本…

嵌入式怎么学?工程师学习路线都在这

在嵌入式系统领域&#xff0c;硬件与软件工程师是不可或缺的重要支柱&#xff0c;分别承担着不同的职责和角色&#xff0c;但两者又紧密相连&#xff0c;共同构成了嵌入式系统的核心。今天本文将详细探讨工程师需要学什么&#xff0c;希望对小伙伴们有所帮助。 嵌入式硬件工程师…

iOS App冷启动优化:Before Main阶段

iOS应用冷启动时&#xff0c;在 UIApplicationMain(argc, argv, nil, appDelegateClassName)方法执行前&#xff0c;主要经历以下阶段&#xff1a; 1. 执行exec&#xff08;&#xff09;启动应用程序进程 2. 加载可执行文件&#xff0c;即将应用程序的Mach-O文件加载到内存…

QT C++实践|超详细数据库的连接和增删改查操作|附源码

0&#xff1a;前言 &#x1faa7; 什么情况需要数据库? 1 大规模的数据需要处理&#xff08;比如上千上万的数据量&#xff09;2 需要把数据信息存储起来&#xff0c;无论是本地还是服务上&#xff0c;而不是断电后数据信息就消失了。 如果不是上面的原因化&#xff0c;一般…

Linux系统中make/Makefile的介绍

文章目录 前言一、make命令二、makefile功能介绍1.makefile文件的编写格式2.hello.c文件内容3.makefile文件4.安装make命令 总结 前言 在linux系统中&#xff0c;我们对项目文件进行处理的时候会不方便&#xff0c;因此我们需要对文件的编译进行自动化处理。 下面就是在Linux系…

Linux第67步_linux字符设备驱动_注册和注销

1、字符设备注册与注销的函数原型” /*字符设备注册的函数原型*/ static inline int register_chrdev(unsigned int major,\ const char *name, \ const struct file_operations *fops) /* major:主设备号&#xff0c;Limnux下每个设备都有一个设备号&#xff0c;设备号分…

接口自动化测试用例如何设计,一文搞定!

说到自动化测试&#xff0c;或者说接口自动化测试&#xff0c;多数人的第一反应是该用什么工具&#xff0c;比如&#xff1a;Python Requests、Java HttpClient、Apifox、MeterSphere、自研的自动化平台等。大家似乎更关注的是哪个工具更优秀&#xff0c;甚至出现“ 做平台的 &…

单点故障解决方案之Smart Link与Monitor Link

-SmartLink技术&#xff0c;创建Smart Link 组。在该组中&#xff0c;加入两个端口。其中1个端口是主端口&#xff0c;也称之为Master端口。另外1个端口是备份端口:也称之为 Slave 端口。 -Monitor Link 组也称之为“监控链路组&#xff0c;由上行端口和下行端口共同组成。下行…

XSS简介及xsslabs第一关

XSS被称为跨站脚本攻击(Cross-site scripting)&#xff0c;由于和CSS(CascadingStyle Sheets)重名&#xff0c;所以改为XSS。 XSS主要速于javascript语言完成恶意的攻击行为&#xff0c;因为javascript可非常灵活的操作html、css和浏览器 XSS就是指通过利用网页开发时留下的漏…

VS Code常用快捷键

前言 对于开发者而言&#xff0c;熟悉快捷键的使用&#xff0c;能够起到事半功倍的作用&#xff0c;提高工作效率。以下是我整理的一份VS Code常用快捷键清单&#xff0c;希望能够帮助到你&#xff0c;欢迎在评论区留下你的常用快捷键&#x1f91e;。 设置VS Code中的键盘快捷…

Mysql的储存引擎

储存引擎介绍 1. 文件系统 操作系统存取数据的一种机制 2. 文件系统类型 不管使用什么文件系统&#xff0c;数据内容不会变化 不同的是&#xff0c;存储空间、大小、速度 3. MySQL存储引擎 可以理解为&#xff0c;MySQL的“文件系统”&#xff0c;只不过功能更加强大 4. MySQL…

【详识JAVA语言】数据类型与变量

字面常量 在上节课HelloWorld程序中&#xff0c; System.Out.println("Hello World")&#xff1b; 语句&#xff0c;不论程序何时运行&#xff0c;输出的都是Hello World&#xff0c;其实"Hello World"就是字面常量。 public class Demo{public static …