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

目录

互斥锁的概念和使用 

线程通信-互斥

 互斥锁的创建和销毁

 申请锁-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.rhkb.cn/news/244657.html

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

相关文章

ClickHouse与Doris数据库比较

概述 都说“实践是检验真理的唯一标准”&#xff0c;光说不练假把式&#xff0c;那么本文就通过实际的测试来感受一下Doris和clickhouse在读写方面的性能差距&#xff0c;看看Doris盛名之下&#xff0c;是否真有屠龙之技&#xff1b;clickhouse长锋出鞘&#xff0c;是否敢缚苍…

【GitHub项目推荐--不错的 Java 开源项目】【转载】

1 基于 Java 的沙盒塔防游戏 Mindustry 是一款用 Java 编写的沙盒塔防游戏。玩家需要建造精密的传送带供应链&#xff0c;提供炮塔弹药&#xff0c;生产建筑材料&#xff0c;保护建筑并抵御敌人。也可以在跨平台多人合作游戏中与朋友一起战斗&#xff0c;或组队进行 PVP 比赛。…

什么品牌洗地机最好?专业旗舰级洗地机推荐

作为一个打工族&#xff0c;很能理解大家对日常清洁繁琐的烦恼&#xff0c;尤其是在忙碌工作后难以有力气打扫卫生。这时候&#xff0c;洗地机就是解决问题的利器了。它不仅方便轻松&#xff0c;还能有效消菌杀毒&#xff0c;助力深度清洁。若你正在为选择哪款洗地机而烦恼&…

【Java IO】设计模式 (装饰者模式)

Java I/O 使用了装饰者模式来实现。 装饰者模式 请参考装饰者模式详解 装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component)&#xff0c;具体组件的方法实现不需要依赖于其它对象&#xff0c;而装饰者组合了一个组件&#xff0c;这样它可以装饰其它装饰者…

初识汇编指令

1. ARM汇编指令 目的 认识汇编, 从而更好的进行C语言编程 RAM指令格式: 了解 4字节宽度 地址4字节对齐 方便寻址 1.1 指令码组成部分 : condition: 高4bit[31:28] 条件码 0-15 &#xff08;16个值 &#xff09; 条件码: 用于指令的 条件执行 , ARM指定绝大部分 都可…

【Midjourney】绘画风格关键词

1.松散素描(Loose Sketch) "Loose sketch"&#xff08;松散素描&#xff09;通常指的是一种艺术或设计中的手绘风格&#xff0c;其特点是线条和形状的表现相对宽松、自由&#xff0c;没有过多的细节和精确度。这样的素描通常用于表达创意、捕捉概念或者作为设计的初步…

视频监控平台EasyCVR增加fMP4流媒体视频格式及其应用场景介绍

近期我们在视频监控管理平台EasyCVR系统中新增了HTTP-FMP4播放协议&#xff0c;今天我们就来聊聊该协议的特点和应用。 fMP4&#xff08;Fragmented MPEG-4&#xff09;是基于MPEG-4 Part 12的流媒体格式&#xff0c;是流媒体的一项重要技术&#xff0c;因为它能通过互联网传送…

【论文阅读 SIGMOD18】Query-based Workload Forecasting for Self-Driving

Query-based Workload Forecasting for Self-Driving Database Management Systems My Summary ABSTRACT Autonomous DBMS的第一步就是能够建模并预测工作负载&#xff0c;以前的预测技术对查询的资源利用率进行建模。然而&#xff0c;当数据库的物理设计和硬件资源发生变化…

Unity SnapScrollRect 滚动 匹配 列表 整页

展示效果 原理: 当停止滑动时 判断Contet的horizontalNormalizedPosition 与子Item的缓存值 相减,并得到最小值&#xff0c;然后将Content horizontalNormalizedPosition滚动过去 使用方式&#xff1a; 直接将脚本挂到ScrollRect上 注意&#xff1a;在创建Content子物体时…

每日一题——LeetCode1313.解压缩编码列表

这么简单的题目要说的这么复杂 nums里每相邻的两个元素nums[i]、nums[j]为一对&#xff0c;nums[i]表示nums[j]的次数 var decompressRLElist function(nums) {let res[]for(let i0,j1;j<nums.length-1;i2,j2){while(nums[i]--){res.push(nums[j])}}return res }; 消耗时…

Unity之Timeline教程

前言 Unity Timeline是Unity的一种时间轴编辑器工具&#xff0c;用于制作和管理游戏中的动画、剧情以及事件触发。它提供了直观的界面&#xff0c;使得开发者可以通过拖放操作轻松创建和编辑时间轴。 Timeline的使用 创建新的Timeline 在Unity中&#xff0c;选择菜单栏的 Wi…

spring-framework6.x版本源码构建

6.x.修改gradle仓库构建 IDEA版本及gradle构建设置 在gradle指定仓库地址/wrapper/dists/找到与gradle wrapper相对应的gradle版本&#xff0c;在gradle的init.d/目录下新建init.gradle文件&#xff0c;内容如下&#xff1a; allprojects{repositories {mavenLocal()maven { …

Dify学习笔记-手册(三)

1、应用构建及提示词 在 Dify 中&#xff0c;一个“应用”是指基于 GPT 等大型语言模型构建的实际场景应用。通过创建应用&#xff0c;您可以将智能 AI 技术应用于特定的需求。它既包含了开发 AI 应用的工程范式&#xff0c;也包含了具体的交付物。 简而言之&#xff0c;一个应…

探索文件与交互:使用PyQt5构建一个高级文件选择器

在当今的应用程序开发中&#xff0c;文件管理和交互是一个重要的组成部分。特别是对于桌面应用程序&#xff0c;提供一个直观、功能丰富的文件选择器是提高用户体验的关键。 本篇博客&#xff0c;我将介绍如何使用Python和PyQt5来构建一个高级的文件选择器&#xff0c;它不仅能…

Java中的this和super

①this 在Java中&#xff0c;this关键字代表当前对象的引用。它可以用于以下几个方面&#xff1a; 引用当前对象的成员变量&#xff1a;使用this关键字可以引用当前对象的成员变量&#xff0c;以区分成员变量和方法参数或局部变量之间的命名冲突。例如&#xff0c;如果一个方法…

java进阶-jvm精讲及实战

深入了解jvm及实战 1.引言2.jvm概念理解1.1什么是jvm1.2 jvm功能1.3 jvm规范及主流版本1.4 jre jdk jvm的区别和联系1.5 jvm组成 2.jvm-字节码文件class2.1 java和class无关性2.2 字节码应用场景2.4 字节码文件打开方式2.3 字节码文件组成2.3.1 一般信息2.3.2 常量池2.3.3 方法…

Vulnhub-dc4

靶场下载 https://download.vulnhub.com/dc/DC-4.zip 信息收集 判断目标靶机的存活地址: # nmap -sT --min-rate 10000 -p- 192.168.1.91 -oN port.nmap Starting Nmap 7.94 ( https://nmap.org ) at 2024-01-21 16:36 CST Stats: 0:00:03 elapsed; 0 hosts completed (1 up…

68. redis计数与限流中incr+expire的坑以及解决办法(Lua+TTL)

文章目录 一、简介二、代码演进第一版代码&#xff08;存在bug隐患&#xff09;第二版代码&#xff08;几乎无隐患&#xff09;第三版代码(完美无瑕&#xff09; 一、简介 在日常工作中&#xff0c;经常会遇到对某种操作进行频次控制或者统计次数的需求&#xff0c;此时常用的…

快速上手的AI工具-文心一言绘画达人

前言 大家好&#xff0c;现在AI技术的发展&#xff0c;它已经渗透到我们生活的各个层面。对于普通人来说&#xff0c;理解并有效利用AI技术不仅能增强个人竞争力&#xff0c;还能在日常生活中带来便利。无论是提高工作效率&#xff0c;还是优化日常任务&#xff0c;AI工具都可…

蓝桥杯---三羊献瑞

观察下面的加法算式: 其中,相同的汉字代表相同的数字,不同的汉字代表不同的数字。 请你填写“三羊献瑞”所代表的4位数字(答案唯一),不要填写任何多余内容。 答案 代码 public class _03三羊献瑞 {public static void main(String[] args) {//c 生 b 瑞 g 献 d 辉…