可重入锁设计

go 实现可重入锁

实际上,Go 语言标准库中的 sync.Mutex 是不可重入的。但是,我们可以基于 sync.Mutex 实现一个可重入锁(ReentrantLock)。下面是一个简单的可重入锁的实现示例:

 

Go

1package main
2
3import (
4	"sync"
5)
6
7type ReentrantMutex struct {
8	mutex     sync.Mutex
9	holder    string
10	recursion int
11}
12
13func (r *ReentrantMutex) Lock() {
14	goroutineID := getGoroutineID() // 假设这是获取当前 goroutine ID 的函数
15
16	r.mutex.Lock()
17	if r.holder == goroutineID {
18		r.recursion++
19	} else {
20		r.holder = goroutineID
21		r.recursion = 1
22	}
23}
24
25func (r *ReentrantMutex) Unlock() {
26	goroutineID := getGoroutineID()
27
28	r.mutex.Lock()
29	defer r.mutex.Unlock()
30
31	if r.holder != goroutineID {
32		panic("attempted unlock from a goroutine that does not hold the lock")
33	}
34
35	r.recursion--
36	if r.recursion == 0 {
37		r.holder = ""
38	}
39}
40
41// 示例性的 getGoroutineID 函数,实际 Go 语言中没有直接提供获取 Goroutine ID 的方法
42func getGoroutineID() string {
43	// 这里仅作为示例,真实环境中需要自己实现或使用第三方库来获取 goroutine ID
44	return "goroutineID" // 真实情况会更复杂
45}
46
47func main() {
48	reentrantLock := &ReentrantMutex{}
49
50	go func() {
51		reentrantLock.Lock()
52		fmt.Println("Goroutine A acquired the lock.")
53		reentrantLock.Lock()
54		fmt.Println("Goroutine A reacquired the lock.")
55		reentrantLock.Unlock()
56		fmt.Println("Goroutine A released one of its locks.")
57		reentrantLock.Unlock()
58		fmt.Println("Goroutine A fully released the lock.")
59	}()
60
61	// 等待上面的 goroutine 执行完成...
62}
63

上述代码定义了一个名为 ReentrantMutex 的结构体,它在内部维护了一个原始的 Mutex 和一些状态变量来跟踪持有锁的 goroutine 以及该 goroutine 对锁的递归获取次数。当同一个 goroutine 请求已经持有的锁时,递归计数器增加;当释放锁时,如果递归计数器大于 1,则递减而不完全释放锁。

请注意,这里的 getGoroutineID() 函数是虚构的,因为在 Go 语言中并没有直接暴露 Goroutine 的唯一标识符。在实际实现中,可能需要通过其他方式来追踪锁的拥有者,例如通过自定义上下文或者关联特定的数据结构等。

go lru缓存

在Go语言中,要实现一个LRU(Least Recently Used)缓存,可以使用标准库或第三方库。这里展示如何使用 container/list 和 map 结合来手动实现一个简单的LRU缓存:

 

Go

1package main
2
3import (
4	"container/list"
5	"fmt"
6)
7
8// LRUCache 结构体定义了一个容量限制的LRU缓存
9type LRUCache struct {
10	capacity int
11	cache    map[int]*list.Element
12	list     *list.List
13}
14
15// CacheItem 用于存储键值对和其在链表中的位置
16type CacheItem struct {
17	key   int
18	value interface{}
19}
20
21// NewLRUCache 创建一个新的LRU缓存实例
22func NewLRUCache(capacity int) *LRUCache {
23	return &LRUCache{
24		capacity: capacity,
25		cache:    make(map[int]*list.Element),
26		list:     list.New(),
27	}
28}
29
30// Get 方法从缓存中获取键对应的值,如果存在则更新其为最近使用
31func (c *LRUCache) Get(key int) (interface{}, bool) {
32	if elem, ok := c.cache[key]; ok {
33		c.list.MoveToFront(elem)
34		return elem.Value.(*CacheItem).value, true
35	}
36	return nil, false
37}
38
39// Put 方法将键值对添加到缓存,并根据容量调整缓存内容
40func (c *LRUCache) Put(key int, value interface{}) {
41	if elem, ok := c.cache[key]; ok {
42		elem.Value.(*CacheItem).value = value
43		c.list.MoveToFront(elem)
44	} else {
45		if c.list.Len() >= c.capacity {
46			delete(c.cache, c.list.Back().Value.(*CacheItem).key)
47			c.list.Remove(c.list.Back())
48		}
49		newElem := c.list.PushFront(&CacheItem{key: key, value: value})
50		c.cache[key] = newElem
51	}
52}
53
54// 示例代码
55func main() {
56	cache := NewLRUCache(3)
57
58	cache.Put(1, "one")
59	cache.Put(2, "two")
60	cache.Put(3, "three")
61
62	fmt.Println(cache.Get(1)) // 输出:("one", true)
63	cache.Put(4, "four")      // 此时,键为1的项因超过容量而被移除
64	fmt.Println(cache.Get(1)) // 输出:(nil, false)
65	fmt.Println(cache.Get(2)) // 输出:("two", true)
66	fmt.Println(cache.Get(3)) // 输出:("three", true)
67	fmt.Println(cache.Get(4)) // 输出:("four", true)
68}

这个实现仅作为基础示例,实际应用中可能需要考虑更多边界条件以及线程安全问题。

另外,Go社区有一些成熟的第三方包如 github.com/hashicorp/golang-lru,它提供了更高效且易于使用的LRU缓存实现。

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

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

相关文章

查看阿里云maven仓中某个库有哪些版本

起因 最近项目上有做视频业务,方案是使用阿里云的短视频服务,其中也有使用到阿里云的上传SDK,过程中有遇一个上传SDK的内部崩溃,崩溃栈如下: Back traces starts. java.lang.NullPointerException: Attempt to invok…

只用一台服务器部署上线(宝塔面板) 前后端+数据库

所需材料 工具:安装宝塔面板服务器至少一台、域名一个 前端:生成dist文件(前端运行build命令) 后端:生成jar包(maven运行package命令) 准备: 打开宝塔面板,点击进入软…

2、安全开发-Python-Socket编程端口探针域名爆破反弹Shell编码免杀

用途:个人学习笔记,欢迎指正! 目录 主要内容: 一、端口扫描(未开防火墙情况) 1、Python关键代码: 2、完整代码:多线程配合Queue进行全端口扫描 二、子域名扫描 三、客户端,服务端Socket编程通信cmd命…

ASCII 编码一览表

ASCII 编码一览表 标准 ASCII 编码共收录了 128 个字符,其中包含了 33 个控制字符(具有某些特殊功能但是无法显示的字符)和 95 个可显示字符。 二进制十进制十六进制字符/缩写解释00000000000NUL (NULL)空字符00000001101SOH (Start Of Hea…

Android中 Gradle与 AGP 版本对应关系表

Android Gradle Plugin Version版本Gradle Version版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 - 2.1.22.10 - 2.132.1.3 - 2.2.32.14.12.3.03.33.0.04.13.1.04.43.2.0 - 3.2.14.63.3.0 - 3.3.34.10.13.4.0 - 3.4.35.1.13.5.0 - 3.5.45.4.13.…

Iceberg从入门到精通系列之二十四:Spark Structured Streaming

Iceberg从入门到精通系列之二十四:Spark Structured Streaming 一、Streaming Reads二、Streaming Writes三、Partitioned table四、流表的维护 Iceberg 使用 Apache Spark 的 DataSourceV2 API 来实现数据源和目录。 Spark DSv2 是一个不断发展的 API,在…

Nginx简单阐述及安装配置

目录 一.什么是Nginx 二.Nginx优缺点 1.优点 2.缺点 三.正向代理与反向代理 1.正向代理 2.反向代理 四.安装配置 1.添加Nginx官方yum源 2.使用yum安装Nginx 3.配置防火墙 4.启动后效果 一.什么是Nginx Nginx(“engine x”)是一个高性能的HTTP…

Linux Zip解压缩命令

Zip 用法 $ zip [-选项] [-b 路径] [-t 日期] [-n 后缀名] [压缩文件列表] [-xi 列表] 默认操作是添加或替换压缩文件列表中的压缩文件条目,压缩文件列表可以包括特殊名称 -,压缩标准输入数据 Zip 是一个创建和管理 zip 文件的压缩工具 Unzip 是一个用…

算法day10

算法day10 20 有效的括号1047 删除字符串中的所有相邻重复性150 逆波兰表达式求值 20 有效的括号 拿到这个题的想法,首先我在想我能不能用数组的操作来扫描做。后来想想,如果这样做那特判也太多了,不好做。然后第二个想法就是用栈来做&…

冒泡排序(Bubble Sort)、快速排序(Quick Sort)和归并排序(Merge Sort)

冒泡排序 冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,依次比较相邻两个元素,如果它们的顺序错误就交换它们。重复多次,直到没有任何一对数字需要交换为止,最终得到有序列表。 冒泡排序的时间复杂度为 O(…

机器学习-基础分类算法-KNN详解

KNN-k近邻算法 k-Nearest Neighbors 思想极度简单应用数学只是少效果好可以解释机器学习算法使用过程中的很多细节问题更完整的刻画机器学习应用的流程 创建简单测试用例 import numpy as np import matplotlib.pyplot as plt raw_data_X [[3.393533211, 2.331273381],[3.1…

ubuntu20.04安装sumo

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 有问题,请大家指出,争取使方法更完善。这只是ubuntu安装sumo的一种方法。一、注意事项1、首先明确你的ubuntu的用户名是什么 二、sumo安装1.…

1.3.。

1、无名管道:是一个特殊的文件,存储于内存中,不在文件系统中展示,适合亲缘进程间的通信; 2、有名管道:与无名管道类似,但该特殊文件能在文件系统中查看,并且时候亲缘和非亲缘进程间的…

基于springboot篮球论坛系统源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

国家博物馆逆向抢票协议

逆向工程的具体步骤可以因项目和目标系统的不同而有所变化。然而,以下是一般逆向工程的一般步骤: 1. 分析目标系统:对待逆向的系统进行调研和了解,包括其架构、功能、使用的技术等方面的信息。 2. 反汇编或反编译:使…

保姆级CDN使用教程,解决可能出现的各种问题

如果你还没有注册雨云(rainyun),可以通过该链接进行注册雨云 - 新一代云服务提供商 通过该链接注册是可以白嫖到优惠券的,可以白嫖CDN。 比直接注册划算。 雨云的cdn在国内表现是非常不错的,而且不需要域名进行备案 在…

从编程中理解:大脑的并行处理与多任务

在编程领域,多线程并行处理是一个重要概念,它允许程序同时执行多个任务以提高效率。这一原理与大脑的并行处理和多任务能力有着异曲同工之妙。现在让我们用Unity C#代码结合金庸武侠小说中的角色来形象地展现这一点。 设想《天龙八部》中的主角段誉,在江湖中身负多种绝世武…

如何创建长期有效的文件二维码?支持多文件批量生成单独二维码

现在很多人为了避免文件通过文件有时效的问题,会将文件生成二维码之后来使用,将文件存入二维码中通过扫码调取云端的储存的数据来实现文件的预览或者下载。那么对于想要学习文件二维码制作的小伙伴,可以学习下面的方法来制作,利用…

Day25 Golang (回溯) 216.组合总和III 17.电话号码的字母组合

//02 216.组合总和III package mainimport "fmt"func combinationSum3(k int, n int) [][]int {// 全局变量path : []int{}res : [][]int{}// 回溯函数var backtracking func(targetSum, sum, k, startindex int)backtracking func(targetSum, sum, k, startindex i…

flask基于django大数据的证券股票分析系统python可视化大屏

证券分析系统采用B/S架构,数据库是MySQL。网站的搭建与开发采用了先进的Python进行编写,使用了Django框架。该系统从两个对象:由管理员和用户来对系统进行设计构建。主要功能包括:个人信息修改,对股票信息、股票买入、…