linux互斥锁(pthread_mutex)知识点总结

news2025/1/6 19:41:32

对于多线程程序来说,我们往往需要对这些多线程进行同步。同步(synchronization)是指在一定的时间内只允许某一个线程访问某个资源。而在此时间内,不允许其它的线程访问该资源。我们可以通过互斥锁(mutex),条件变量(condition variable)和读写锁(reader-writer lock)来同步资源。

与互斥锁相关API

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

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

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

1. 创建及销毁互斥锁

#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,否则返回错误编号

  要用默认的属性初始化互斥量,只需把attr设置为NULL。  

  2. 加锁及解锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
// 返回:若成功返回0,否则返回错误编号

  如果线程不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0,否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY。

示例代码:

#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data = 0;


pthread_mutex_t mutex;


void *func1(void *arg)
{
    int i;

    pthread_mutex_lock(&mutex);
    for(i=0;i<5;i++){
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("t1:param is %d\n",*((int *)arg));
        sleep(1);
    }
    pthread_mutex_unlock(&mutex);

}

void *func2(void *arg)
{

    pthread_mutex_lock(&mutex);

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

    pthread_mutex_unlock(&mutex);

}

void *func3(void *arg)
{

    pthread_mutex_lock(&mutex);

    printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t3:param is %d\n",*((int *)arg));

    pthread_mutex_unlock(&mutex);

}

int main()
{
    int ret;
    int param = 100;
    pthread_t t1;
    pthread_t t2;
    pthread_t t3;

    pthread_mutex_init(&mutex, NULL);

    
    ret = pthread_create(&t1, NULL, func1,(void *)&param);
    if(ret == 0){
        printf("main:create t1 success\n");
    }

    ret = pthread_create(&t2, NULL, func2,(void *)&param);
    if(ret == 0){
        printf("main:create t2 success\n");
    }

    ret = pthread_create(&t3, NULL, func3,(void *)&param);
    printf("main:%ld\n",(unsigned long)pthread_self());

    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    pthread_mutex_destroy(&mutex);

    return 0;
}


编译结果:t1会被main函数打断,但是不会被t2,t3打断,t1运行后t2,t3才能运行

我们也用互斥锁限制共享资源的访问

例如:让g_data = 3时,在线程t1退出

#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data = 0;

pthread_mutex_t mutex;


void *func1(void *arg)
{
    printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
    printf("t1:param is %d\n",*((int *)arg));
    
    pthread_mutex_lock(&mutex);
    while(1){


        printf("t1: %d\n",g_data++);    
        sleep(1);

        if(g_data == 3){
            pthread_mutex_unlock(&mutex);
            printf("t1 quit================================\n");
//            pthread_exit(NULL);
            exit(0);
        }
    }

}

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

        printf("t2: %d\n",g_data);
        pthread_mutex_lock(&mutex);
        g_data++;
        pthread_mutex_unlock(&mutex);    
        sleep(1);
    }
}

int main()
{
    int ret;
    int param = 100;
    pthread_t t1;
    pthread_t t2;

    pthread_mutex_init(&mutex,NULL);

    ret = pthread_create(&t1, NULL, func1,(void *)&param);
    if(ret == 0){
        printf("main:create t1 success\n");
    }

    ret = pthread_create(&t2, NULL, func2,(void *)&param);
    if(ret == 0){
        printf("main:create t2 success\n");
    }

    printf("main:%ld\n",(unsigned long)pthread_self());
    while(1){
    
        printf("main: %d\n",g_data);    
        sleep(1);
    }

    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
}


编译结果:

可以写个shell脚本验证一下编译结果,先简单介绍一下shell脚本吧

Shell脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。shell script是一种解释型语言,必须由解释器来执行这些脚本,执行时,解释器将脚本一行一行地转换为代码。

这个解释器就是Shell,它是一个用 C 语言编写的程序。常见的Shell有Bourne Shell(/usr/bin/sh或/bin/sh)和Bourne Again Shell(/bin/bash),sh由Steve Bourne开发,是Unix 标准默认的shell,bash由Brian Fox和Chet Ramey共同开发完成,是Linux标准默认的shell。


在linux中可以使用vim来编写shell script,通常使用.sh作为扩展名,sh代表shell。下面是一个简单的shell脚本:

//运行三次

编写完shell脚本,在执行脚本前我们需要给脚本添加执行权限,命令如下:

接着运行:

编译结果:

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

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

相关文章

1、Vue.js---Vue核心

目录 Vue是什么 什么是渐进式&#xff1a; Vue 的特点 与其它 JS 框架的关联 Vue 周边库 搭建Vue开发环境&#xff08;2种方式&#xff09; 1、直接用 2、NPM Hello小案例 小结&#xff1a; 模板语法 代码 小结&#xff1a; 数据绑定 代码&#xff1a; 小结&…

11、渗透性测试及验收测试

目录 什么是安全测试 安全测试与常规测试的区别 SQL注入漏洞 SQL注入漏洞会带来以下几种常见的后果&#xff1a; SQL注入漏洞攻击流程 注入点类型 SQL注入的防范措施 XSS跨站脚本漏洞 XSS原理解析 XSS类型 1、反射型XSS 2、存储型XSS 3、存储型XSS 查找XSS漏洞的…

1.4. 运算符与表达式

在 Java 中&#xff0c;运算符是用于执行特定操作的符号&#xff0c;而表达式是由变量、常量和运算符组成的一段代码&#xff0c;用于计算值。本节将介绍 Java 中的常用运算符和表达式的使用。 1.4.1. 算术运算符 Java 支持以下算术运算符&#xff1a; 加法&#xff08;&…

C语言基础习题讲解

C语言基础习题讲解 运算符判断简单循环 运算符 1. 设计一个程序, 输入三位数a, 分别输出个,十,百位. (0<a<1000) 样例输入: 251 样例输出: 2 5 1 #include <stdio.h> int main() {int input 0;int x 0;int y 0;int z 0;scanf("%d", &input);x …

chatgpt赋能python:Python三次方函数介绍

Python三次方函数介绍 Python是一种流行的编程语言&#xff0c;用于各种应用程序&#xff0c;包括数据分析和机器学习。Python三次方函数是Python语言中的一个内置函数&#xff0c;可用于计算一个数字的三次方。本文将介绍Python三次方函数的相关内容并提供一些示例。 Python…

chatgpt赋能python:Python三个数相加的方法与应用

Python三个数相加的方法与应用 在现代编程语言中&#xff0c;Python是一个非常流行的语言。Python语言的的特点是易学易用、功能强大、语法简洁等。在Python中&#xff0c;运算也是非常方便的&#xff0c;特别是对于数值计算。本文将讨论如何在Python中实现三个数的加法运算&a…

LeetCode高频算法刷题记录11

文章目录 1. 最大正方形【中等】1.1 题目描述1.2 解题思路1.3 代码实现 2. 在排序数组中查找元素的第一个和最后一个位置【中等】2.1 题目描述2.2 解题思路2.3 代码实现 3. 搜索二维矩阵 II【中等】3.1 题目描述3.2 解题思路3.3 代码实现 4. 翻转二叉树【简单】4.1 题目描述4.2…

POWERLINK协议在stm32单片机+w5500移植成功经验分享

连续折腾了多个晚上&#xff0c;又趁周末又花了一天时间&#xff0c;终于把powerlink协议移植成功到单片机上啦。本想放弃&#xff0c;但想了下不管我能不能用上&#xff0c;结个尾吧&#xff0c;分享给有需要的人。放弃并不难&#xff0c;但坚持一定很酷。为了移植测试这个协议…

Arcgis小技巧【13】——和数据统计相关的各种工具

在Arcgis中可以通过属性表中字段的【统计】功能或使用统计相关的工具对属性表进行数据统计。 在Arcgis工具箱中有一组【统计分析】工具集&#xff0c;不仅包含对属性数据执行标准统计分析&#xff08;例如平均值、最小值、最大值和标准差&#xff09;的工具&#xff0c;也包含…

表的增删改查

目录 表的增删改查create(创建)单行数据 全列插入多行数据 指定列插入插入否则更新替换 retrieve(读取)SELECT 列全列查询指定列查询查询字段为表达式为查询结果指定别名结果去重 WHERE 条件英语不及格的同学及英语成绩 ( < 60 )&#xff08;<&#xff09;语文成绩在 […

个人博客-SpringBoot+Vue3项目实战(6)- 二次封装Axios

目录 前言新建axiosUtil.js 文件基本配置统一URL.env文件与环境变量示例参考资料 请求头超时时间 request 拦截器response 拦截器统一Api管理测试 前言 在上文中&#xff0c;我们封装了统一的后端数据返回结果&#xff0c;有了标准化的接口数据&#xff0c;我们就可以针对它&a…

【Linux性能优化】你知道什么是平衡负载么

什么是平衡负载 首先大家思考一下&#xff0c;当你发现自己的服务变慢时&#xff0c;你会首先使用什么命令来排查&#xff1f;我通常做的第一件事&#xff0c;就是执行top或者uptime命令来了解系统的负载情况。比如像下面这样&#xff0c;我在命令行里输入top命令&#xff0c;…

Springboot +spring security,创建SpringSecurity项目

一.简介 搭建第一个Spring Security项目&#xff0c;看看如何利用Spring Security来保护Java Web项目。 二. 创建SpringSecurity项目 我们这边使用idea进行创建。 2.1创建一个基于Maven的Project项目。 2.2设置项目名称和存储位置 2.3添加项目依赖 在pom.xml文件中&#x…

LeetCode 128 最长连续序列

LeetCode 128 最长连续序列 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/longest-consecutive-sequence/description/ 博主Github&#xff1a;https://github.com/GDUT-Rp/LeetCode 题目&#xff1a; 给定一个未排…

【双系统ubuntu安装指引】配置一个顺手的深度学习环境

文章目录 前言1. 前置安装 前言 版本&#xff1a;ubuntu20.04 桌面版 normal安装 第一件事&#xff0c;切换源&#xff1a;换成阿里源 https://blog.csdn.net/u010092716/article/details/125832062 第二件事输入法安装&#xff0c;指引在这里 https://blog.csdn.net/q54434431…

JMeter性能测试:JMeter多用户并发模拟及压测结果分析

目录 JMeter设置 JMeter线程组 JMeter压测实例 View Results Tree Aggregate Report 命令行方式执行压测 jtl文件解析 JMeter多用户并发模拟 JMeter设置 多用户并发数的多少与计算机内存有关&#xff0c;设置 jmeter.bat (Windows) 或者 jmeter.sh (Linux)&#xff1a;…

chapter6:SpringBoot与Docker

1. 简介 Docker是一个开源的轻量级应用容器引擎, 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到Linux机器中实现虚拟化。(沙箱机制) Docker支持将软件编译成一个镜像&#xff1b;然后在镜像中各种软件做好配置&#xff0c;将镜像…

《数据库系统概论》期末考试手写笔记汇总+考试注意事项+反思(超全整理总结!!!)

&#xff08;一&#xff09;期末考试手写笔记汇总 笔记内容为期末考试前整理&#xff08;结合测试题PPT作业题目课本&#xff09; 很多内容为纯手写&#xff0c;非常的全乎&#xff0c;预祝你期末可以考个好成绩&#x1f339; 第二章第三章&#xff08;25分&#xff09; (…

JS 深度克隆的实现方法

方法一&#xff1a;正统做法&#xff08;扩展性高&#xff0c;推荐&#xff09; function test() { this.a 1; this.b 2; } test.prototype.c 3; // 原型上的属性 const obj new test(); console.log("原对象", obj); console.log("克隆后的对象", dee…

Flume系列:案例-Flume负载均衡和故障转移

目录 Apache Hadoop生态-目录汇总-持续更新 逻辑&#xff1a; 2&#xff1a;案例需求-实现故障转移 3&#xff1a;实现步骤&#xff1a; 2.1&#xff1a;实现flume1.conf 2.2&#xff1a;实现flume2.conf - 端口4141 2.3&#xff1a;实现flume3.conf - 端口4142 3&#…