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

news2024/12/26 0:13:17

目录

互斥锁的概念和使用 

线程通信-互斥

 互斥锁的创建和销毁

 申请锁-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);
    }
}

 运行结果:

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

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

相关文章

Kubeadm安装单master多node节点K8S集群

kubeadm安装k8s1.25版本集群步骤 环境说明实验环境规划集群搭建规划 初始化安装k8s集群的实验环境安装虚拟机更新yum源和操作系统配置机器主机名配置主机hosts文件&#xff0c;相互之间通过主机名互相访问配置主机之间无密码登录关闭交换分区swap&#xff0c;提升性能修改机器内…

漏洞补丁修复之openssl版本从1.1.1q升级到1.1.1t以及python版本默认2.7.5升级到2.7.18新版本和Nginx版本升级到1.24.0

​ 一、Openssl升级 1、查看Openssl安装的版本 openssl version 2、查看Openssl路径 which openssl 3、上传openssl安装包到服务器:openssl-1.1.1t.tar.gz,并且解压,安装: mv /usr/local/openssl /usr/local/backup_openssl_1.1.1q_20240120 mkdir /usr/local/openssl tar…

LeetCode.2765. 最长交替子数组

题目 2765. 最长交替子数组 分析 为了得到数组 nums 中的最长交替子数组的长度&#xff0c;需要分别计算以每个下标结尾的最长交替子数组的长度。为了方便处理&#xff0c;计算过程中需要考虑长度等于 1 的最长交替子数组&#xff0c;再返回结果时判断最长交替子数组的长度…

【AI视野·今日Robot 机器人论文速览 第七十五期】Thu, 11 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Thu, 11 Jan 2024 Totally 16 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Analytical Model and Experimental Testing of the SoftFoot: an Adaptive Robot Foot for Walking over Obstacles and Irre…

MMagic调试(训练)dreambooth

时间&#xff1a;2024.1.23 1.dreambooth配置文件 dreambooth在mmagic中的路径&#xff1a; configs/dreambooth本文以dreambooth.py 为例 configs/dreambooth/dreambooth.py2.下载数据集 下载数据集并保存至data/dreambooth/&#xff0c;数据集&#xff1a; https://dri…

[BUUCTF]-PWN:babyfengshui_33c3_2016解析

又是一道堆题&#xff0c;先看保护 关键信息是32位&#xff0c;没开pie 直接看ida 大致是alloc创建堆块&#xff0c;free释放堆块&#xff0c;show查看堆块内容&#xff0c;fill填充堆块内容 其他的都没啥关键的要讲&#xff0c;但alloc那里非常需要解析一下 解释如上图 再具…

npm install运行报错npm ERR! gyp ERR! not ok问题解决

执行npm install的时候报错&#xff1a; npm ERR! path D:..\node_modules\\**node-sass** npm ERR! command failed ...npm ERR! gyp ERR! node -v v20.11.0 npm ERR! gyp ERR! node-gyp -v v3.8.0 npm ERR! gyp ERR! not ok根据报错信息&#xff0c;看出时node-sass运行出现…

基于taro搭建小程序多项目框架

前言 为什么需要这样一个框架&#xff0c;以及这个框架带来的好处是什么&#xff1f; 从字面意思上理解&#xff1a;该框架可以用来同时管理多个小程序&#xff0c;并且可以抽离公用组件或业务逻辑供各个小程序使用。当你工作中面临这种同时维护多个小程序的业务场景时&#xf…

前端面试题-(浏览器内核,CSS选择器优先级,盒子模型,CSS硬件加速,CSS扩展)

前端面试题-(浏览器内核&#xff0c;CSS选择器优先级&#xff0c;盒子模型&#xff0c;CSS硬件加速&#xff0c;CSS扩展&#xff09; 常见的浏览器内核CSS选择器优先级盒子模型CSS硬件加速CSS扩展 常见的浏览器内核 内核描述Trident(IE内核)主要用在window系统中的IE浏览器中&…

【论文阅读|2024 WACV 多目标跟踪Deep-EloU】

论文阅读|2024 WACV 多目标跟踪Deep-EloU 摘要1 引言&#xff08;Introduction&#xff09;2 相关工作&#xff08;Related Work&#xff09;2.1 基于卡尔曼滤波器的多目标跟踪算法&#xff08;Multi-Object Tracking using Kalman Filter&#xff09;2.2 基于定位的多目标跟踪…

Elasticsearch:Simulate ingest API

Ingest pipeline 为我们摄入数据提供了极大的方便。在我之前的文章中&#xff0c;有非常多的有关 ingest pipeline 的文章。请详细阅读文章 “Elastic&#xff1a;开发者上手指南”。针对一组提供的文档执行摄取管道&#xff0c;可以选择使用替代管道定义。 Simulate ingest AP…

如何查找SpringBoot应用中的请求路径(不使用idea)

背景 昨天有个同事向我咨询某个接口的物理表是哪个&#xff0c;由于公司业务较多、这块业务的确不是我负责的&#xff0c;也没有使用idea不能全局搜索(eclipse搜不到jar内的字符串)&#xff0c;也就回复了不清楚。 除了自己写代码输出servlet的路径和类外&#xff0c;发现了一…

【C++】list容器功能模拟实现

介绍 上一次介绍了list队容器的迭代器模拟&#xff0c;这次模拟实现list的简单功能&#xff0c;尤其要注意构造函数、析构函数、以及赋值运算符重载的实现。 list容器需要接纳所有类型的数据&#xff0c;因此&#xff0c;结构设置与迭代器设置同理&#xff0c;需要引入结点&…

邮件服务支持Exchange协议,资产历史账号支持设置保留数量,JumpServer堡垒机v3.10.2 LTS版本发布

2024年1月22日&#xff0c;JumpServer开源堡垒机正式发布v3.10.2 LTS版本。JumpServer开源项目组将对v3.10 LTS版本提供长期的支持和维护&#xff0c;并定期迭代发布小版本。欢迎广大社区用户升级至v3.10 LTS版本&#xff0c;以获得更佳的使用体验。 在v3.10.2 LTS版本中&…

LeetCode203 移除链表元素

203. 移除链表元素 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5] 示例 2&#…

简单高效 Learn LaTeX 008 - LaTex Font Color 字体与颜色 (32 mins)

在LaTeX中进行字体和颜色的设置&#xff1a; https://www.ixigua.com/7298100920137548288?id7304094068840071730&logTag3418d8469157c468c60b

开始学习vue2(Vue方法)

一、过滤器 过滤器&#xff08;Filters&#xff09;是 vue 为开发者提供的功能&#xff0c;常用于文本的格式 化。过滤器可以用在两个地方&#xff1a;插值表达式 和 v-bind 属性绑定。 过滤器应该被添加在 JavaScript 表达式的尾部&#xff0c;由“管道符 ”进行 调用&#…

春招冲刺第二天——SQL学习

春招冲刺第二天 前言 MySQL学习&#xff1a;哔哩哔哩参考视频&#xff1a; 【中字】SQL进阶教程 | 史上最易懂SQL教程&#xff01;10小时零基础成长SQL大师 第一章 Mysql安装 视频前三节有教程&#xff0c;或自行查阅&#xff0c;不做赘述 课程资料和数据库数据的网盘&…

苹果眼镜(Vision Pro)的开发者指南(6)-实战应用场景开发 - 游戏、协作、空间音频、WebXR

第一部分:【构建游戏和媒体体验】 了解如何使用visionOS在游戏和媒体体验中创建真正身临其境的时刻。游戏和媒体可以利用全方位的沉浸感来讲述令人难以置信的故事,并以一种新的方式与人们联系。将向你展示可供你入门的visionOS游戏和叙事开发途径。了解如何使用RealityKit有…

windows .vscode的json文件配置 CMake 构建项目 调试窗口中文设置等

一、CMake 和 mingw64的安装和环境配置 二、tasks.json和launch.json文件配置 tasks.json {"version": "2.0.0","options": {"cwd": "${workspaceFolder}/build"},"tasks": [{"type": "shell&q…