go语言sync包的学习(Mutex、WaitGroup、Cond)

mb6066e165689bf · · 289 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

go语言sync包的学习(Mutex、WaitGroup、Cond)

 

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main;
 
import (
    "fmt"
    "sync"
    "runtime"
    "time"
)
 
//加锁,注意锁要以指针的形式传进来,不然只是拷贝
func total1(num *int, mu *sync.Mutex, ch chan bool) {
    mu.Lock();
    for i := 0; i < 1000; i++ {
        *num += i;
    }
    ch <- true;
    mu.Unlock();
}
 
//不加锁
func total2(num *int, ch chan bool) {
    for i := 0; i < 1000; i++ {
        *num += i;
    }
    ch <- true;
}
 
//Lock、Unlock与RLock、RUnlock不能嵌套使用
func total3(num *int, rwmu *sync.RWMutex, ch chan bool) {
    for i := 0; i < 1000; i++ {
        rwmu.Lock();
        *num += i;
        rwmu.Unlock();
 
        if(i == 500) {
            //读锁定
            rwmu.RLock();
            fmt.Print(*num, " ");
            rwmu.RUnlock();
        }
    }
    ch <- true;
}
 
func printNum(num int, cond *sync.Cond) {
    cond.L.Lock();
    if num < 5 {
        //num小于5时,进入等待状态
        cond.Wait();
    }
    //大于5的正常输出
    fmt.Println(num);
    cond.L.Unlock();
}
 
func main() {
    //Once.Do()保证多次调用只执行一次
    once := sync.Once{};
    ch := make(chan bool, 3);
    for i := 0; i < 3; i++ {
        go func(n int) {
            once.Do(func() {
                //只会执行一次,因为闭包引用了变量n,最后的值为2
                fmt.Println(n)
            });
            //给chan发送true,表示执行完成
            ch <- true;
        }(i);
    }
    for i := 0; i < 3; i++ {
        //读取三次chan,如果上面三次没执行完会一直阻塞
        <-ch;
    }
 
    //互斥锁,保证某一时刻只能有一个访问对象
    mutex := sync.Mutex{};
    ch2 := make(chan bool, 20);
    //使用多核,不然下面的结果会一样
    runtime.GOMAXPROCS(runtime.NumCPU());
    num1 := 0;
    num2 := 0;
    for i := 0; i < 10; i++ {
        go total1(&num1, &mutex, ch2);
    }
    for i := 0; i < 10; i++ {
        go total2(&num2, ch2);
    }
    for i := 0; i < 20; i++ {
        <-ch2;
    }
    //会发现num1与num2计算出的结果不一样
    //而num1的结果才是正确的,因为total2没有加锁,导致多个goroutine操作num时发生数据混乱
    fmt.Println(num1, num2);
 
    //读写锁,多了读锁定,和读解锁,让多个goroutine同时读取对象
    rwmutex := sync.RWMutex{};
    ch3 := make(chan bool, 10);
    num3 := 0;
    for i := 0; i < 10; i++ {
        go total3(&num3, &rwmutex, ch3);
    }
    for i := 0; i < 10; i++ {
        <-ch3;
    }
    fmt.Println(num3);
 
    //组等待,等待一组goroutine的结束
    wg := sync.WaitGroup{};
    //增加计数器
    wg.Add(10);
    for i:= 0; i< 10; i++ {
        go func(n int) {
            fmt.Print(n, " ");
            //这里表示该goroutine执行完成
            wg.Done();
        }(i);
    }
    //等待所有线程执行完成
    wg.Wait();
 
    fmt.Println("");
 
    //条件等待
    mutex2 := sync.Mutex{};
    //使用锁创建一个条件等待
    cond := sync.NewCond(&mutex2);
 
    for i := 0; i < 10; i++ {
        go printNum(i, cond);
    }
 
    time.Sleep(time.Second * 1);
    //等待一秒后,我们先唤醒一个等待,输出一个数字
    cond.L.Lock()
    cond.Signal();
    cond.L.Unlock();
    time.Sleep(time.Second * 1);
    //再次待待一秒后,唤醒所有,输出余下四个数字
    cond.L.Lock()
    cond.Broadcast();
    cond.L.Unlock();
    time.Sleep(time.Second * 1);
}



有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:mb6066e165689bf

查看原文:go语言sync包的学习(Mutex、WaitGroup、Cond)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

289 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传