ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

并发编程

2022-06-20 13:03:57  阅读:159  来源: 互联网

标签:wg 10 编程 sync var 并发 Mutex go


Go 并发原语
并发问题出现的原因---> 在Go开发中如何监测到这个问题---> Go 是如何解决的

互斥锁

https://songlh.github.io/paper/go-study.pdf
问题描述:

package main
import(
	"fmt"
	"sync"
)
func main(){
	var count = 0
	// 使用 WaitGroup等待 10个goroutine 完成
	var wg sync.WaitGroup
	wg.Add(10)
	for i :=0;i< 10; i++{
		go func ()  {
			defer wg.Done()
			// 对变量count 执行10次加1
			for j:=0;j<100000; j++{
				count++
			}
		}()
	}

// 等10个goroutine 完成
wg.Wait()
fmt.Println(count)
}

image
出错原因
分析代码---> 这段代码一共启动了10个goroutine, 这10个goroutine 可能同时进行count++的操作
如何监测

Data Race Detector:https://go.dev/doc/articles/race_detector

image
groutine8 对内存地址0x00c00012c078 有度的操作 (go文件的第17行), 同时groutine7 对内存地址有写操作(go文件的第17行)
Data Race Deltector 只能在代码触发并发问题后才给予反馈
go tool compile -race -S .\testMutext.go 可以查看 go 编译后的代码,之前了解到, 产生并发问题是在 count++ 附近,重点关注一下

代码中增加了runtine.recefuncenter, runtime.recered, runtime.recewrite, runtime.recefuncexit等监测data race问题
如何解决
Go标准库中, package sync提供了锁相关的一系列同步原语,Mutex 实现了该包提供的一个 Locker的接口

type Locker interface {
    Lock()
    Unlock()
}

互斥锁Mutex 提供了两个方法 Lock和Unlock,进入临界区前调用Lock方法, 退出临界区的时候调用Unlock方法

func(m *Mutex)Lock()
func(m*Mutex)Unlock()

Mutex 嵌入到Struct中使用

type Counter struct{
    mu sync.Mutex
    Count unint64
}

使用Mutex解决并发锁问题的几种代码形式
1.

package main
import (
	"fmt"
	"sync"
)
func main(){
	// 互斥锁保护计数器
	var mu sync.Mutex
	// 计数器的值
	var count = 0
	
	// 辅助变量,用来确认所有的goroutine 都完成
	var wg sync.WaitGroup
	wg.Add(10)

	// 启动 10个gourontine
	for i:=0; i<10; i++{
		go func ()  {
			defer wg.Done()
			// 累加 10万次
			for j:=0; j< 100000;j++{
				mu.Lock()
				count++
				mu.Unlock()
			}
		}()
	}
	wg.Wait()
	fmt.Println(count)
}
package main

import (
    "fmt"
    "sync"
)

func main() {
    
    var counter Counter
    var wg sync.WaitGroup
    wg.Add(10)
    for i := 0; i < 10; i++ {
        go func() {
            defer wg.Done()
            for j := 0; j < 100000; j++ {
                counter.Lock()
                counter.Count++
                counter.Unlock()
                
            }
        }()
    }
    wg.Wait()
    fmt.Println(counter.Count)
}
type Counter struct{
    sync.Mutex
    Count uint64
}
package main
import(
	"fmt"
	"sync"
)
func main(){
	//封装好的计数器
	var counter Counter 

	var wg sync.WaitGroup
	wg.Add(10)

	//启动 10个goroutine 
	for i:=0;i<10;i++{
		go func(){
			defer wg.Done()
			// 执行10万次 累加
			for j:=0; j<100000;j++{
				counter.Incr()  //受到锁保护的方法
			}
		}()
	}
	wg.Wait()
	fmt.Println(counter.Count())
}

// 线程安全的计数器类型
type Counter struct{
	CounterType int
	Name string

	mu sync.Mutex
	count uint64
}
// 加1 的方法,内部使用互斥锁保护
func (c *Counter) Incr(){
	c.mu.Lock()
	c.count++
	c.mu.Unlock()
}

// 得到计数器的值,也需要锁保护

func (c *Counter) Count() uint64{
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.count
}

标签:wg,10,编程,sync,var,并发,Mutex,go
来源: https://www.cnblogs.com/stormliu/p/16283044.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有