线程的同步和互斥学习笔记

目录

互斥锁的概念和使用 

线程通信-互斥

 互斥锁的创建和销毁

 申请锁-pthread_mutex_lock

 释放锁-pthread_mutex_unlock

读写锁的概念和使用

死锁的避免


互斥锁的概念和使用 

线程通信-互斥

临界资源

  • 一次只允许一个任务(进程、线程)访问的共享资源

概念:

        不能同时访问的资源,比如写文件,只能由一个线程写,同时写会写乱。

        比如外设打印机,打印的时候只能由一个程序使用。

        外设基本上都是不能共享的资源。

        生活中比如卫生间,同一时间只能由一个人使用。

临界区

  • 访问临界资源的代码

互斥机制

  • mutex互斥锁,任务访问临界资源前申请锁,访问完后释放锁

 互斥锁的创建和销毁

两种方法创建互斥锁,静态方式和动态方式: 

动态方式: 

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,
    const pthread_mutexattr_t *attr);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象
  • attr互斥锁属性,NULL表示缺省属性
  • man函数出现No manual entry for pthread_mutex_xxx解决方法:apt-get install manpages-posix-dev

 静态方式:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

 锁的销毁:

int pthread_mutex_destory(pthread_mutex_t *mutex)

在linux中,互斥锁并不占用任何资源,因此LinuxThreads中的pthread_mutex_destory()除了检查锁状态以外(锁定状态则返回EBUSY)没有其他动作。

 申请锁-pthread_mutex_lock

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象
  • pthread_mutex_lock如果无法获得锁,任务阻塞
  • pthread_mutex_trylock如果无法获得锁,返回EBUSY而不是挂起等待

 释放锁-pthread_mutex_unlock

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 成功时返回0,失败时返回错误码
  • mutex指向要初始化的互斥锁对象

 示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁
void *func1(void *arg)
{
    pthread_detach(pthread_self());
    printf("This is child thread1\n");
    char str[] = "I write func1 line\n";
    char c;
    int i = 0;
    //pthread_mutex_t mutex1;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        while(i < strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_mutex_unlock(&mutex);
        i = 0;
        usleep(1);
    }
    
    pthread_exit("func1 exit");
}
void *func2(void *arg)
{
    pthread_detach(pthread_self());
    printf("This is child thread2\n");
    char str[] = "You read func1 thread\n";
    char c;
    int i = 0;
    //pthread_mutex_t mutex2;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        while(i < strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_mutex_unlock(&mutex);
        i = 0;
        usleep(1);
    }
    pthread_exit("func2 exit");
}
int main()
{ 
    pthread_t tid1,tid2;
    void *retv;
    int i;   
    fp = fopen("1.txt","a+");
    if(fp == NULL)
    {
        perror("fopen");
        return 0;
    }
    pthread_create(&tid1,NULL,func1,NULL);
    pthread_create(&tid2,NULL,func2,NULL);
    while(1)
    {
        sleep(1);
    }
}

运行结果:

读写锁的概念和使用

 必要性:提高线程执行效率

特性:

  • 写者:写者使用写锁,如果当前没有读者,也没有其他写者,写者立即获得写锁;否则写者将等待,直到没有读者和写者。
  • 读者:读者使用读锁,如果当前没有写者,读者立即获得读锁;否则读者等待,直到没有写者。

 注意:

  • 同一时刻只有一个线程可以获得写锁,同一时刻可以有多个线程获得读锁
  • 读写锁出于写锁状态时,所有试图对读写锁加锁的线程,不管是读者试图加读锁,还是写者试图加写锁,都会被阻塞。
  • 读写锁处于读锁状态时,有写者试图加写锁时,之后的其他线程的读锁请求会被阻塞,以避免写者长时间的不写锁
  •  初始化一个读写锁        pthread_rwlock_init
  • 读锁定读写锁                pthread_rwlock_rdlock
  • 非阻塞读锁定                pthread_rwlock_tryrdlock
  • 写锁定读写锁                pthread_rwlock_wrlock
  • 非阻塞写锁定                pthread_rwlock_trywrlock
  • 解锁读写锁                    pthread_rwlock_unlock
  • 释放读写锁                    pthread_rwlock_destroy

 示例代码:

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


pthread_rwlock_t rwlock;

FILE *fp;
void * read_func(void *arg){
    pthread_detach(pthread_self());
    printf("read thread\n");
    char buf[32]={0};
    while(1){
        //rewind(fp);
        pthread_rwlock_rdlock(&rwlock);
        while(fgets(buf,32,fp)!=NULL){
            printf("%d,rd=%s\n",(int)arg,buf);
            usleep(1000);
        }
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }

}



void *func2(void *arg){
    pthread_detach(pthread_self());
    printf("This func2 thread\n");
    
    char str[]="I write func2 line\n";
    char c;
    int i=0;
    while(1){
        pthread_rwlock_wrlock(&rwlock);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            usleep(1);
            i++;
        }
        pthread_rwlock_unlock(&rwlock);
        i=0;
        usleep(1);

    }

    pthread_exit("func2 exit");

}

void *func(void *arg){
    pthread_detach(pthread_self());
    printf("This is func1 thread\n");
    char str[]="You read func1 thread\n";
    char c;
    int i=0;
    while(1){
        pthread_rwlock_wrlock(&rwlock);
        while(i<strlen(str))
        {
            c = str[i];
            fputc(c,fp);
            i++;
            usleep(1);
        }
        pthread_rwlock_unlock(&rwlock);
        i=0;
        usleep(1);

    }
    pthread_exit("func1 exit");
}


int main(){
    pthread_t tid1,tid2,tid3,tid4;
    void *retv;
    int i;
    fp = fopen("1.txt","a+");
    if(fp==NULL){
        perror("fopen");
        return 0;
    }
    pthread_rwlock_init(&rwlock,NULL);
    pthread_create(&tid1,NULL,read_func,1);
    pthread_create(&tid2,NULL,read_func,2);
    pthread_create(&tid3,NULL,func,NULL);
    pthread_create(&tid4,NULL,func2,NULL);
    while(1){    
        sleep(1);
    } 

}

死锁的避免

  • 锁越少越好,最好使用一把锁
  • 调整好锁的顺序
  • 使锁进行错位

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
FILE *fp;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;  //多个文件需要多个锁

void *func1(void *arg)
{
    pthread_detach(pthread_self());
    printf("This is child thread1\n");
    char str[] = "I write func1 line\n";
    char c;
    int i = 0;
    //pthread_mutex_t mutex1;
    while (1)
    {
        pthread_mutex_lock(&mutex2);
        printf("%d,I get lock2\n",(int)arg);
        sleep(1);
        pthread_mutex_lock(&mutex);
        printf("%d,I get 2 locks\n",(int)arg);
        pthread_mutex_unlock(&mutex);
        pthread_mutex_unlock(&mutex2);
        sleep(10);
    }
    
    pthread_exit("func1 exit");
}
void *func2(void *arg)
{
    pthread_detach(pthread_self());
    printf("This is child thread2\n");
    char str[] = "You read func1 thread\n";
    char c;
    int i = 0;
    //pthread_mutex_t mutex2;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        printf("%d,I get lock1\n",(int)arg);
        sleep(1);
        pthread_mutex_lock(&mutex2);
        printf("%d,I get 2 locks\n",(int)arg);

        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex);
        usleep(10);
    }
    pthread_exit("func2 exit");
}
int main()
{ 
    pthread_t tid1,tid2;
    void *retv;
    int i;   
    fp = fopen("1.txt","a+");
    if(fp == NULL)
    {
        perror("fopen");
        return 0;
    }
    pthread_create(&tid1,NULL,func1,1);
    sleep(5);
    pthread_create(&tid2,NULL,func2,2);
    while(1)
    {
        sleep(1);
    }
}

 运行结果:

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

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

相关文章

基于springboot+vue的台球管理系统

摘要 台球管理系统是一款基于Spring Boot和Vue.js技术栈构建的现代化系统&#xff0c;旨在提供全面而高效的台球场馆管理服务。该系统通过整合前后端技术&#xff0c;实现了场馆预约、会员管理、比赛统计等核心功能&#xff0c;为台球场馆管理员和玩家提供了便捷、智能的管理和…

leetcode第 381 场周赛最后一题 差分,对称的处理

第 381 场周赛 - 力扣&#xff08;LeetCode&#xff09;最后一题3017. 按距离统计房屋对数目 II - 力扣&#xff08;LeetCode&#xff09; dijkstra超时了&#xff0c;看了灵神的解题方法力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台&#xff0c;其…

Linux中普通用户如何使用sudo指令提升权限

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 普通用户为何无法使用sudo&#xff1f; 我们来看一下具体操作 总结 前言 世上有两种耀眼的光芒&#xff0c;一种是正在升起的太阳&#xff0c;一种是正在努力…

Facebook的区块链之路:探秘数字货币的未来

近年来&#xff0c;Facebook一直在积极探索区块链技术&#xff0c;并逐渐将目光聚焦在数字货币领域。从推出Libra项目到改名为Diem&#xff0c;Facebook一直在寻求在数字货币领域取得突破性进展。本文将深入探讨Facebook的区块链之路&#xff0c;揭示其对数字货币未来发展的影响…

LLM自回归解码

在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;大型语言模型&#xff08;LLM&#xff09;如Transformer进行推理时&#xff0c;自回归解码是一种生成文本的方式。在自回归解码中&#xff0c;模型在生成下一个单词时会依赖于它之前生成的单词。 使用自回归解码的公式…

数字拆分--完全背包问题

一、题目 https://acm.ecnu.edu.cn/problem/3034/ 二、思路 本来算法就很弱&#xff0c;加上很久没刷题&#xff0c;做这道题真的是一言难尽~ 一开始我以为是找规律写递推式&#xff0c;写到f(9)的时候就觉得不对劲&#xff0c;又想了一会&#xff0c;还是没想到&#xff0…

【linux】Linux编译器-gcc/g++使用

先写一段代码演示 1 #include<stdio.h>2 #define M 1003 int main()4 {5 printf("hello linux");6 printf("hello linux");7 //printf("hello linux");8 //printf("hello linux");9 //printf("hello linux");10 //pri…

Win10 如何用powershell写个WOL开机脚本

环境&#xff1a; Win10 专业版 问题描述&#xff1a; Win10 如何用powershell写个WOL开机脚本 解决方案&#xff1a; 1.脚本内容 $mac b1-10-18-52-11-12 $macBytes $mac -split - | ForEach-Object { [byte](0x $_) } $broadcastAddress [byte[]](1..6 | ForEach-O…

【江科大】STM32:中断系统(理论)

文章目录 中断系统为什么要使用中断中断优先级中断嵌套STM32的中断系统如何管理这些中断NVIC的结构![请添加图片描述](https://img-blog.csdnimg.cn/c77b038fd63a4ddfbcd3b86f6dfe596b.png) 优先级窗口看门狗&#xff08;WWDG&#xff09;&#xff1a;外部中断模块的特性&#…

unity刷新grid,列表

获取UIGrid 组件&#xff0c;更新列表 listParent.GetComponent().repositionNow true;

【STM32】STM32F4中USB的CDC虚拟串口(VCP)使用方法

文章目录 一、前言二、STM32CubeMX生成代码2.1 选择芯片2.2 配置相关模式2.3 设置时钟频率2.4 生成代码2.5 编译并下载代码2.6 结果2.7 问题 三、回环测试3.1 打开工程3.2 添加回环代码3.3 编译烧录并测试 四、出现问题和解决方法4.1 烧录总是要自己插拔USB4.2 自己生成的工程没…

Python基础之数据库操作

一、安装第三方库PyMySQL 1、在PyCharm中通过 【File】-【setting】-【Python Interpreter】搜索 PyMySQL进行安装 2、通过PyCharm中的 Terminal 命令行 输入: pip install PyMySQL 注&#xff1a;通过pip安装&#xff0c;可能会提示需要更新pip&#xff0c;这时可执行&#…

could‘t get post build model module: xx.app.main variant:xxdebbug

当androidStudio进行run应用的时候,报错&#xff1a; couldt get post build model module: xx.app.main variant:xxdebbug后经过排查&#xff0c;方案如下&#xff1a; invalidate caches 清除缓存&#xff08;全部勾选&#xff09;&#xff1b; 删除 .gradle 目录&#xff…

【JS逆向学习】某壁纸下载(ast混淆)

逆向目标 目标网址&#xff1a;https://bz.zzzmh.cn/index逆向接口一&#xff1a;https://api.zzzmh.cn/bz/v3/getData逆向接口二&#xff1a;https://cdn2.zzzmh.cn/wallpaper/origin/0d7d8d691e644989b72ddda5f695aca2.jpg?response-content-dispositionattachment&aut…

eNSP学习——理解ARP及Proxy ARP

目录 名词解释 实验内容 实验目的 实验步骤 实验拓扑 配置过程 基础配置 配置静态ARP 名词解释 ARP (Address Resolution Protocol)是用来将IP地址解析为MAC地址的协议。ARP表项可以分为动态和静态两种类型。   动态ARP是利用ARP广播报文&#xff0c;动态执行并自动进…

RT-DETR 模型改进 | AKConv:具有任意采样形状和任意参数数量的卷积核

基于卷积操作的神经网络在深度学习领域取得了显著的成果,但标准卷积操作存在两个固有缺陷。一方面,卷积操作受限于局部窗口,无法捕捉其他位置的信息,而其采样形状是固定的。另一方面,卷积核的大小固定为kk,呈固定的正方形形状,而参数数量往往随大小呈平方增长。显然,不…

TensorRT英伟达官方示例解析(二)

系列文章目录 TensorRT英伟达官方示例解析&#xff08;一&#xff09; TensorRT英伟达官方示例解析&#xff08;二&#xff09; 文章目录 系列文章目录前言一、03-BuildEngineByTensorRTAPI1.1 建立 Logger&#xff08;日志记录器&#xff09;1.2 Builder 引擎构建器1.3 Netwo…

关于 LLM,你了解多少?

LLM定义 大语言模型&#xff08;LLM&#xff09;是一种基于大量文本数据训练的深度学习模型。它的主要功能是生成自然语言文本或理解语言文本的含义。这些模型可以处理多种自然语言任务&#xff0c;如文本分类、问答、对话等&#xff0c;是通向人工智能的一条重要途径。 LLM发…

什么是通配监听端口? 什么是通配监听IP?

什么是通配监听端口? 监听端口&#xff1a; 指的是服务器或服务开启的特定TCP或UDP端口号&#xff0c;等待客户端连接或发送数据。TCP/IP协议下每个端口只能由一个服务独占监听&#xff0c;一个服务或应用会指定监听特定的一个或多个端口来接收客户端的连接请求。 例如 Web…

计算机网络基础概念解释

​ 1. 什么是网络 随着时代的发展&#xff0c;越来越需要计算机之间互相通信&#xff0c;共享软件和数据&#xff0c;即以多个计算机协同⼯作来完成业务&#xff0c;于是有了网络互连。 网络互连&#xff1a;将多台计算机连接在⼀起&#xff0c;完成数据共享。 数据共享本质是…