多线程编程4:linux线程同步(信号量和读写锁)

信号量

  • linux信号量API:

    #include <semaphore.h>
    // 定义信号量对象sem_t sem;
    /*初始化信号量- 第一个参数:信号量地址- 第二个参数:线程同步(0),进程同步(非0)- 第三个参数:初始化信号量资源数(>=0),如果设置为0,线程会被阻塞- 成功返回0,失败返回-1
    */
    int sem_init(sem_t* sem, int pshared, unsigned int value);
    // 销毁信号量
    int sem_destroy(sem_t* sem);
    // 给信号量资源+1,会唤醒其他wait阻塞的线程
    int sem_post(sem_t* sem);
    // 获取一个信号量里面的资源(资源-1),资源数为0阻塞
    int sem_wait(sem_t* sem);
    // 尝试获取,若资源数为0,不阻塞直接返回错误码
    int sem_trywait(sem_t* sem);
    // 超时获取资源,资源数为0,只需阻塞abs_timeout时间
    int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout);
    // 查看当前信号量资源数,sval是传出参数
    int sem_getvalue(sem_t *sem,int *sval);
    
  • TIP:

    • 当资源数只有1的时候,不管多少个线程,可以工作的线程只有一个,其他线程拿不到资源会被阻塞,或者说是有多少资源,唤醒多少线程与mutex不同,mutex是大家一起强, 与条件变量不同,条件变量要么只唤醒一个要么全部唤醒。
    • 当资源数大于1的时候,需要配合mutex维持共享资源的顺序访问
    • 使用sem_timedwait的时候,时间参数不能设置为NULL,不然运行的时候会产生崩溃

读写锁

  • 背景:
    很多情况下,对于共享变量的访问,读操作远多于写操作,这种情况下读操作是不需要同步的,可以安全的并发访问,如果使用mutex导致读的性能严重下降

  • 初始化销毁读写锁

    #include <pthread.h>
    pthread_rwlock_t rwlock;//定义读写锁对象
    int pthread_rwlock_init(pthread_rwlock_t* rwlock,const pthread_rwlockattr_t* attr);// 初始化读写锁
    int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);// 销毁读写锁
    
  • 申请读锁的API

    /*读锁是打开的,加锁锁定读操作,写操作加锁久会阻塞读锁可以重复加锁
    */
    int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);//加读锁
    //尝试加锁,失败返回错误号EBUSY
    int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);
    //超时加锁,超时返回错误号ETIMEOUT
    int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock, const struct timespec* abstime);
    
  • 申请写锁的API

    // 如果读写锁没有被加锁,则可以加写锁,如果被了读或者写锁,直接上锁
    int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);//加写锁
    int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);//尝试加锁
    int pthread_rwlock_timedwrlock(pthread_rwlock_t* rwlock, const struct timespec* abstime);//超时加锁
    
  • 解锁(读锁和写锁都是一个接口):

    int pthread_rwlock_unlock (pthread_rwlock_t* rwlock);
    
  • 读写锁属性设置API:

#include <pthread.h>
// 定义属性对象
pthread_rwlockattr_t attr;
// 初始化属性变量
int pthread_rwlockattr_init(pthread_rwlockattr_t* attr);
// 销毁属性变量
int pthread_rwlockattr_destroy(pthread_rwlockattr_t* attr);
// 设置属性
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t* attr, int pref);
// 查询属性
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t* attr, int* pref);
// pref可取值
enum
{//读者优先(即同时请求读锁和写锁时,请求读锁的线程优先获得锁)PTHREAD_RWLOCK_PREFER_READER_NP, //不要被名字所迷惑,也是读者优先PTHREAD_RWLOCK_PREFER_WRITER_NP, //写者优先(即同时请求读锁和写锁时,请求写锁的线程优先获得锁)PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,                 PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP
};
  • TIP:

    • 如果当前读写锁被加读锁,则其他线程可以继续请求读锁,而请求写锁的都会被阻塞
    • 如果当前读写锁被加写锁,则其他线程请求的读操作和写操作都会阻塞
    • 如果使用读锁,可能需要考虑临界区的原子性,比如cout多线程可能会串掉
    • 读写锁默认属性是读锁优先,可以通过设置读写锁属性,设置写锁优先
  • 读写锁,写锁优先实列:

    #include <pthread.h>
    #include <unistd.h>
    #include <iostream>int resourceID = 0;
    pthread_rwlock_t myrwlock;void* read_thread(void* param)
    {    while (true){//请求读锁pthread_rwlock_rdlock(&myrwlock);std::cout << "read thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl;//使用睡眠模拟读线程读的过程消耗了很久的时间sleep(1);pthread_rwlock_unlock(&myrwlock);}return NULL;
    }void* write_thread(void* param)
    {while (true){//请求写锁pthread_rwlock_wrlock(&myrwlock);++resourceID;std::cout << "write thread ID: " << pthread_self() << ", resourceID: " << resourceID << std::endl;pthread_rwlock_unlock(&myrwlock);//放在这里增加请求读锁线程获得锁的几率sleep(1);}return NULL;
    }int main()
    {pthread_rwlockattr_t attr;pthread_rwlockattr_init(&attr);//设置成请求写锁优先pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);pthread_rwlock_init(&myrwlock, &attr);//创建5个请求读锁线程pthread_t readThreadID[5];for (int i = 0; i < 5; ++i){pthread_create(&readThreadID[i], NULL, read_thread, NULL);}//创建一个请求写锁线程pthread_t writeThreadID;pthread_create(&writeThreadID, NULL, write_thread, NULL);pthread_join(writeThreadID, NULL);for (int i = 0; i < 5; ++i){pthread_join(readThreadID[i], NULL);}pthread_rwlock_destroy(&myrwlock);return 0;
    }
    

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

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

相关文章

PostgreSQL:string_agg 多列值聚合成一列

PostgreSQL:string_agg 多列值聚合成一列 string_agg是PostgreSQL中的一个聚合函数&#xff0c;用于将一组值连接为一个字符串。它接受两个参数&#xff1a;要连接的值和连接符。 语法如下&#xff1a; string_agg(expression, delimiter)其中&#xff0c;expression是要连接…

uni-app:实现分页功能,单击行获取此行指定数据,更改行样式

效果&#xff1a; 分段解析代码 分页功能实现&#xff1a; 一、标签 1、搜索栏-模糊查询 <!-- 搜索框--><form action"" submit"search_wip_name"><view class"search_position"><view class"search"><…

SpringBoot项目中的web安全防护

最近这个月公司对项目进行了几次安全性扫描&#xff0c;然后扫描出来了一些安全漏洞&#xff0c;所以最近也一直在修复各种安全漏洞&#xff0c;还有就是最近在备考软考高级系统架构设计师&#xff0c;也刚好复习到了网络安全这一个章节&#xff0c;顺便将最近修复的安全漏洞总…

Debian/Ubuntu 安装 Chrome 和 Chrome Driver 并使用 selenium 自动化测试

截至目前&#xff0c;Chrome 仍是最好用的浏览器&#xff0c;没有之一。Chrome 不仅是日常使用的利器&#xff0c;通过 Chrome Driver 驱动和 selenium 等工具包&#xff0c;在执行自动任务中也是一绝。相信大家对 selenium 在 Windows 的配置使用已经有所了解了&#xff0c;下…

cmd 实现启动mysql时保留窗口

因为mysql启动后, 只有在任务管理器里能看到进程, 关的时候还需要找一下 所以基于 start cmd /k 命令实现了该效果 :: Author: admin :: Date: 2022-08-30 :: Version v1.2 :: ::启动 :: :: echo off::配置变量 set mysqlC:\mysql-5.7.38-winx64\bin\mysqld.exe::打印配置…

Jmeter 压测工具使用手册[详细]

1. jemter 简介 jmeter 是 apache 公司基于 java 开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简 单。因为 jmeter 是 java 开发的&#xff0c;所以运行的时候必须先…

在 3ds Max 中使用相机映射将静止图像转换为实时素材

推荐&#xff1a; NSDT场景编辑器 助你快速搭建可二次开发的3D应用场景 1. 在 Photoshop 中准备图像 步骤 1 这是我将在教程中使用的静止图像。 这是我的静态相机纸箱的快照。 静止图像 步骤 2 打开 Photoshop。将图像导入 Photoshop。 打开 Photoshop 步骤 3 单击套索工…

windows物理机 上安装centos ,ubuntu,等多个操作系统的要点

一、摘要 一般情况下&#xff0c;我们的笔记本或工作电脑都默认安装windows 分几个区&#xff0c;当下是win7 win8 win 10 win11 等&#xff0c;突然我们有需求需要安装个centos &#xff0c;后面我们应当怎么做&#xff0c;要点是什么&#xff1f;一定要根据网上的贴子一步步来…

Word导出高清PDF

通过word导出pdf清晰度较高的方法_word如何导出高分辨率pdf_Perishell的博客-CSDN博客通过打印机属性设置&#xff0c;让word打印出比较高清的pdf_word如何导出高分辨率pdfhttps://blog.csdn.net/weixin_45390670/article/details/129228568?ops_request_misc%257B%2522reques…

学习笔记|C251|STC32G单片机视频开发教程(冲哥)|第三集:开发环境搭建和程序下载

文章目录 1.STC-ISP软件的下载2.STC32手册下载3.PDF阅读器下载4.学会PDF阅读器查阅手册5.跟着手册搭建C251开发环境Tips:如何同时安装Keil的C51、C251和MDK 6.程序包的下载7.第一个工程的编译和下载 原作者/主讲人&#xff1a;冲哥 原始视频地址 1.STC-ISP软件的下载 STC-ISP …

应急响应-主机后门webshell的排查思路(webshell,启动项,隐藏账户,映像劫持,rootkit后门)

0x00 windows主机后门排查思路 针对主机后门windows&#xff0c;linux&#xff0c;在对方植入webshell后&#xff0c;需要立即响应&#xff0c;排查出后门位置&#xff0c;以及排查对外连接&#xff0c;端口使用情况等等 排查对外连接状态&#xff1a; 借助工具&#xff1a;p…

数据结构 | 线性数据结构——列表

目录 一、无序列表抽象数据类型 二、实现无序列表&#xff1a;链表 2.1 Node类 2.2 UnorderedList类 三、有序列表抽象数据类型 四、实现有序列表 列表是元素的集合&#xff0c;其中每一个元素都有一个相对于其他元素的位置。更具体地说&#xff0c;这种列表成为无序列表…

GDB Debug

使用gdb带着参数启动程序 在gdb中启动程序并传递命令行参数&#xff1a; gdb ./my_program (gdb) run arg1 arg2 arg3 这将在gdb中启动程序"my_program"&#xff0c;并将参数"arg1"、"arg2"和"arg3"传递给程序。 在启动gdb之前&…

后端进阶之路——浅谈Spring Security用户、角色、权限和访问规则(三)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

代码随想录算法训练营day48

文章目录 Day48 打家劫舍题目思路代码 打家劫舍II题目思路代码 打家劫舍 III题目思路代码递归去偷动态规划法&#xff08;状态标记递归&#xff09; Day48 打家劫舍 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 题目 你是一个专业的小偷&#xff0c;计划偷窃沿街…

两数相加 II

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数字都不会以零开头。 示例1&#xff1a; 输入&#xff1a;l1 [7,2,4,3], l2 [5,6,4] 输…

什么是 webpack?

Webpack 介绍 什么是 webpack&#xff1f; :::tip 官方描述 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个…

【SCSS】网格布局中的动画

效果 index.html <!DOCTYPE html> <html><head><title> Document </title><link type"text/css" rel"styleSheet" href"index.css" /></head><body><div class"container">&l…

C 语言高级2-多维数组,结构体,递归操作

1. 多维数组 1.1 一维数组 元素类型角度&#xff1a;数组是相同类型的变量的有序集合内存角度&#xff1a;连续的一大片内存空间 在讨论多维数组之前&#xff0c;我们还需要学习很多关于一维数组的知识。首先让我们学习一个概念。 1.1.1 数组名 考虑下面这些声明&#xff1…

react中使用redux-persist做持久化储存

某天下午折腾着玩的 – 笔记 安装相关依赖 npm install reduxjs/toolkit redux-persist redux react-redux// store.jsx import { configureStore, getDefaultMiddleware } from "reduxjs/toolkit"; import { persistStore, persistReducer } from "redux-per…