GO语言:临界资源安全问题_go fmt

本文讨论了并发编程中因共享数据引发的临界资源安全问题,通过实例展示了多个goroutine同时访问同一数据可能导致的问题,并介绍了使用sync包中的Mutex来解决资源同步和锁定的问题。
摘要由CSDN通过智能技术生成

能够发现一处被多个goroutine共享的数据。

二、临界资源安全问题

并发本身并不复杂,但是因为有了资源竞争的问题,就使得我们开发出好的并发程序变得复杂起来,因为会引起很多莫名其妙的问题。

如果多个goroutine在访问同一个数据资源的时候,其中一个线程修改了数据,那么这个数值就被修改了,对于其他的goroutine来讲,这个数值可能是不对的。

举个例子,我们通过并发来实现火车站售票这个程序。一共有100张票,4个售票口同时出售。

我们先来看一下示例代码:

package main
​
import (
    "fmt"
    "math/rand"
    "time"
)
​
//全局变量
var ticket = 10 // 100张票
​
func main() {
    /*
    4个goroutine,模拟4个售票口,4个子程序操作同一个共享数据。
     */
    go saleTickets("售票口1") // g1,100
    go saleTickets("售票口2") // g2,100
    go saleTickets("售票口3") //g3,100
    go saleTickets("售票口4") //g4,100
​
    time.Sleep(5*time.Second)
}
​
func saleTickets(name string) {
    rand.Seed(time.Now().UnixNano())
    //for i:=1;i<=100;i++{
    //  fmt.Println(name,"售出:",i)
    //}
    for { //ticket=1
        if ticket > 0 { //g1,g3,g2,g4
            //睡眠
            time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
            // g1 ,g3, g2,g4
            fmt.Println(name, "售出:", ticket)  // 1 , 0, -1 , -2
            ticket--   //0 , -1 ,-2 , -3
        } else {
            fmt.Println(name,"售罄,没有票了。。")
            break
        }
    }
}
​

我们为了更好的观察临界资源问题,每个goroutine先睡眠一个随机数,然后再售票,我们发现程序的运行结果,还可以卖出编号为负数的票。

分析:

我们的卖票逻辑是先判断票数的编号是否为负数,如果大于0,然后我们就进行卖票,只不过在卖票钱先睡眠,然后再卖,假如说此时已经卖票到只剩最后1张了,某一个goroutine持有了CPU的时间片,那么它再片段是否有票的时候,条件是成立的,所以它可以卖票编号为1的最后一张票。但是因为它在卖之前,先睡眠了,那么其他的goroutine就会持有CPU的时间片,而此时这张票还没有被卖出,那么第二个goroutine再判断是否有票的时候,条件也是成立的,那么它可以卖出这张票,然而它也进入了睡眠。。其他的第三个第四个goroutine都是这样的逻辑,当某个goroutine醒来的时候,不会再判断是否有票,而是直接售出,这样就卖出最后一张票了,然而其他的goroutine醒来的时候,就会陆续卖出了第0张,-1张,-2张。

这就是临界资源的不安全问题。某一个goroutine在访问某个数据资源的时候,按照数值,已经判断好了条件,然后又被其他的goroutine抢占了资源,并修改了数值,等这个goroutine再继续访问这个数据的时候,数值已经不对了。

三、临界资源安全问题的解决

要想解决临界资源安全的问题,很多编程语言的解决方案都是同步。通过上锁的方式,某一时间段,只能允许一个goroutine来访问这个共享数据,当前goroutine访问完毕,解锁后,其他的goroutine才能来访问。

我们可以借助于sync包下的锁操作。

示例代码:

package main
​
import (
    "fmt"
    "math/rand"
    "time"
    "sync"
)
​
//全局变量
var ticket = 10 // 100张票
​
var wg sync.WaitGroup
var matex sync.Mutex // 创建锁头
​
func main() {
    /*
    4个goroutine,模拟4个售票口,4个子程序操作同一个共享数据。
     */
    wg.Add(4)
    go saleTickets("售票口1") // g1,100
    go saleTickets("售票口2") // g2,100
    go saleTickets("售票口3") //g3,100
    go saleTickets("售票口4") //g4,100
    wg.Wait()              // main要等待。。。
​
    //time.Sleep(5*time.Second)
}
​
func saleTickets(name string) {
    rand.Seed(time.Now().UnixNano())
    defer wg.Done()


### 给大家的福利


**零基础入门**


对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。


![](https://img-blog.csdnimg.cn/img_convert/95608e9062782d28f4f04f821405d99a.png)


同时每个成长路线对应的板块都有配套的视频提供:


![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a91b9e8100834e9291cfcf1695d8cd42.png#pic_center)


因篇幅有限,仅展示部分资料


网络安全面试题


![](https://img-blog.csdnimg.cn/img_convert/80674985176a4889f7bb130756893764.png)


绿盟护网行动


![](https://img-blog.csdnimg.cn/img_convert/9f3395407120bb0e1b5bf17bb6b6c743.png)


还有大家最喜欢的黑客技术


![](https://img-blog.csdnimg.cn/img_convert/5912337446dee53639406fead3d3f03c.jpeg)


**网络安全源码合集+工具包**


![](https://img-blog.csdnimg.cn/img_convert/5072ce807750c7ec721c2501c29cb7d5.png)


![](https://img-blog.csdnimg.cn/img_convert/4a5f4281817dc4613353c120c9543810.png)

**所有资料共282G**,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以点击这里获取](https://bbs.csdn.net/topics/618540462)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值