time包中的定向通道
(⼀)、Timer结构体
- 计时器类型表示单个事件。当计时器过期时,当前时间将被发送到C上(C是⼀
个只读通道<-chan time.Time,该通道中放⼊的是Time结构体),除⾮计时器是
AfterFunc创建的。计时器必须使⽤NewTimer或AfterFunc创建。 - Timer结构体的源码
// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
C <-chan Time
r runtimeTimer
}
(⼆)、NewTimer函数
- NewTimer创建⼀个新的计时器,它会在⾄少持续时间d之后将当前时间发送
到其通道上。 - NewTimer()函数的源码
// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
func NewTimer(d Duration) *Timer - 示例代码
//.创建计时器
timer1 := time.NewTimer(5 * time.Second)
fmt.Printf("%Tn", timer1) /
var wg sync.WaitGroup
wg.Add(4)
go saleTickets("售票⼝1", &wg) //g1
go saleTickets("售票⼝2", &wg) //g2
go saleTickets("售票⼝3", &wg) //g3
go saleTickets("售票⼝4", &wg) //g4
wg.Wait()
fmt.Println("所有⻋票已售空。程序结束!") }
func saleTickets(name string, wg *sync.WaitGroup) {
for {
mutex.Lock()
if tickts > 0 {
time.Sleep(1 * time.Second)
fmt.Println(name, ":", tickts) //1
tickts--
} else {
fmt.Println(name, ",结束卖票。。")
mutex.Unlock()
break
}
mutex.Unlock() //解锁
}
wg.Done()
}
(⼆)、读写互斥锁RWMutex
- 原型
type RWMutex struct {
w Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
readerSem uint32 // semaphore for readers to wait for completing writers
readerCount int32 // number of pending readers
readerWait int32 // number of departing readers
}
RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯⼀个写⼊者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程⽆关,可以由不同的线程加读取锁/写⼊和解读取锁/写⼊锁。
锁定的规则:
读写锁的使⽤中:写操作都是互斥的、读和写是互斥的、读和读不互斥。
理解为:
可以多个goroutine同时读取数据,但是写只允许⼀个goroutine写数据。 - Mutex中的⽅法
- func (rw *RWMutex) Lock()
Lock⽅法将rw锁定为写⼊状态,禁⽌其他线程读取或者写⼊。 - func (rw *RWMutex) Unlock()
Unlock⽅法解除rw的写⼊锁状态,如果m未加写⼊锁会导致运⾏时错误。 - func (rw *RWMutex) RLock()
RLock⽅法将rw锁定为读取状态,禁⽌其他线程写⼊,但不禁⽌读取。 - func (rw *RWMutex) RUnlock()
Runlock⽅法解除rw的读取锁状态,如果m未加读取锁会导致运⾏时错误。 - func (rw *RWMutex) RLocker() Locker
Rlocker⽅法返回⼀个互斥锁,通过调⽤rw.Rlock和rw.Runlock实现了Locker接⼝。
- 示例代码
func main() {
var rwm sync.RWMutex
for i := 1; i <= 3; i++ {
go func(i int) {
fmt.Printf("goroutine %d,尝试读锁定。。n", i)
rwm.RLock()
fmt.Printf("goroutine %d,已经读锁定了。。n", i)
time.Sleep(5 * time.Second)
fmt.Printf("goroutine %d,读解锁。。n", i)
rwm.RUnlock()
}(i)
}
time.Sleep(1*time.Second)
fmt.Println("main..尝试写锁定。。")
rwm.Lock()
fmt.Println("main。。已经写锁定了。。")
rwm.Unlock()
fmt.Printf("main。。写解锁。。。") }
sync包中的条件变量Cond
(⼀)、条件变量Cond
- 原型
type Cond struct {
noCopy noCopy
// L is held while observing or changing the condition
L Locker
notify notifyList
checker copyChecker
}
Cond实现了⼀个条件变量,⼀个线程集合地,供线程等待或者宣布某事件的发⽣。
每个Cond实例都有⼀个相关的锁(⼀般是Mutex或RWMutex类型的值),它必须在改变条件时或者调⽤Wait⽅法时保持锁定。Cond可以创建为其他结构体的字段,Cond在开始使⽤后不能被拷⻉。条件变量:sync.Cond,多个goroutine等待或接受通知的集合地 - Cond中的⽅法
- func NewCond(l Locker) Cond
使⽤锁l创建⼀个Cond。Cond条件变量,总是要和锁结合使⽤。 - func (c *Cond) Broadcast()
Broadcast唤醒所有等待c的线程。调⽤者在调⽤本⽅法时,建议(但并⾮必须)保持c.L的锁定。 - func (c *Cond) Signal()
Signal唤醒等待c的⼀个线程(如果存在)。调⽤者在调⽤本⽅法时,建议(但并⾮必须)保持c.L的锁定。发送通知给⼀个⼈。 - func (c *Cond) Wait()
Wait⾃⾏解锁c.L并阻塞当前线程,在之后线程恢复执⾏时,Wait⽅法会在返回前锁定c.L。和其他系统不同,Wait除⾮被Broadcast或者Signal唤醒,不会主动返回。⼴播给所有⼈。
因为线程中Wait⽅法是第⼀个恢复执⾏的,⽽此时c.L未加锁。调⽤者不应假设Wait恢复时条件已满⾜,相反,调⽤者应在循环中等待:
- 示例代码
func main() {
var mutex sync.Mutex
cond := sync.Cond{L:&mutex}
condition := false
go func() {
time.Sleep(1*time.Second)
cond.L.Lock()
fmt.Println("⼦goroutine已经锁定。。。")
fmt.Println("⼦goroutine更改条件数值,并发送通知。。")
condition = true//更改数值
cond.Signal() //发送通知:⼀个goroutine
fmt.Println("⼦gorutine。。。继续。。。")
time.Sleep(5*time.Second)
fmt.Println("⼦groutine解锁。。")
cond.L.Unlock()
}()
cond.L.Lock()
fmt.Println("main..已经锁定。。。")
if !condition{
fmt.Println("main.。即将等待。。。")
//wait()
// 1.wait尝试解锁,
// 2.等待--->当前的groutine进⼊了阻塞状态,等待被唤醒:signal(),broadcast()
// 3.⼀旦被唤醒后,⼜会锁定
cond.Wait()
fmt.Println("main.被唤醒。。")
}
fmt.Println("main。。。继续")
fmt.Println("main..解锁。。。")
cond.L.Unlock()
}