通过锁请求时间同步获取锁
Acquire lock synchronized by lock asking time
我有一个带有 goroutine 的程序,我们将调用 mainRoutine 来锁定资源,在另一侧的其他 goroutines of fired 我们将命名为 goroutine-0 goroutine-1 goroutine-2 .... 这个例程试试要获取锁,在 mainRoutine 停止后我需要我的另一个 goroutine 以同步方式获取锁,我的意思是我想要 goroutine-0 然后 goroutine-1 ...
面对这个问题,我所做的是 time.Time 的一部分,其中填充了启动 goroutine 的 time.Now(),并使用了 sync.Cond。
一些代码示例来说明:
package main
import (
"fmt"
"sync"
"time"
)
func condition(myTime time.Time, timeSlice []time.Time) bool {
for _, v := range timeSlice {
if myTime.After(v) {
return false
}
}
return true
}
func removeFromSlice(myTime time.Time, timeSlice []time.Time) {
var place int
for i, v := range timeSlice {
if myTime.Equal(v) {
place = i
break
}
}
timeSlice = append(timeSlice[:place], timeSlice[place+1:]...)
}
func main() {
var m sync.Mutex
c := sync.NewCond(&m)
c.L.Lock()
fmt.Println("Locker locked")
go func() {
time.Sleep(time.Second * 1)
c.L.Unlock()
fmt.Println("Locker unlocked")
}()
var wg sync.WaitGroup
var timeSlice []time.Time
wg.Add(100)
for i := 0; i < 100; i++ {
now := time.Now()
timeSlice = append(timeSlice, now)
time.Sleep(time.Nanosecond * 1) // ensure there's at leat 1 nanosec of diff between 2 time.Now
go func(i int, myTime time.Time) {
fmt.Printf("Before %d %d\n", i, myTime.Unix())
c.L.Lock()
for !condition(myTime, timeSlice) {
c.Wait()
}
c.L.Unlock()
removeFromSlice(myTime, timeSlice)
c.Broadcast()
wg.Done()
fmt.Printf("After done %d\n", i)
}(i, now)
}
wg.Wait()
fmt.Println("Hello, playground")
}
我不认为这是做这种事情的正确方法它看起来很 hacky,有没有更好的方法?
-- 编辑 --
在@Vorsprung 的回答之后,我认为在我的案例中最好的方法是制作一个 func 片段,它总是调用片段的第一个元素
package main
import (
"fmt"
"sync"
)
func makeFunc(id int) func() {
return func() {
fmt.Printf("called %d\n", id)
}
}
func main() {
var wg sync.WaitGroup
var funcSlice []func()
var m sync.Mutex
for i := 0; i < 5; i++ {
funcSlice = append(funcSlice, makeFunc(i))
wg.Add(1)
go func() {
defer wg.Done()
m.Lock()
defer m.Unlock()
funcSlice[0]()
funcSlice = funcSlice[1:]
}()
}
wg.Wait()
fmt.Println("finished")
}
给goroutines一个内部id,然后让它们按顺序互相调用。下面是如何工作的示例
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var c [5]chan int
for i := range c {
c[i] = make(chan int)
wg.Add(1)
go func(id int) {
defer wg.Done()
f := <-c[id]
fmt.Println("called from ", f, ". My id ", id)
if id < 4 {
fmt.Println(id+1, " next")
c[id+1] <- id
}
fmt.Println("ending ", id)
}(i)
}
c[0] <- 99
wg.Wait()
fmt.Println("bye")
}
我有一个带有 goroutine 的程序,我们将调用 mainRoutine 来锁定资源,在另一侧的其他 goroutines of fired 我们将命名为 goroutine-0 goroutine-1 goroutine-2 .... 这个例程试试要获取锁,在 mainRoutine 停止后我需要我的另一个 goroutine 以同步方式获取锁,我的意思是我想要 goroutine-0 然后 goroutine-1 ... 面对这个问题,我所做的是 time.Time 的一部分,其中填充了启动 goroutine 的 time.Now(),并使用了 sync.Cond。 一些代码示例来说明:
package main
import (
"fmt"
"sync"
"time"
)
func condition(myTime time.Time, timeSlice []time.Time) bool {
for _, v := range timeSlice {
if myTime.After(v) {
return false
}
}
return true
}
func removeFromSlice(myTime time.Time, timeSlice []time.Time) {
var place int
for i, v := range timeSlice {
if myTime.Equal(v) {
place = i
break
}
}
timeSlice = append(timeSlice[:place], timeSlice[place+1:]...)
}
func main() {
var m sync.Mutex
c := sync.NewCond(&m)
c.L.Lock()
fmt.Println("Locker locked")
go func() {
time.Sleep(time.Second * 1)
c.L.Unlock()
fmt.Println("Locker unlocked")
}()
var wg sync.WaitGroup
var timeSlice []time.Time
wg.Add(100)
for i := 0; i < 100; i++ {
now := time.Now()
timeSlice = append(timeSlice, now)
time.Sleep(time.Nanosecond * 1) // ensure there's at leat 1 nanosec of diff between 2 time.Now
go func(i int, myTime time.Time) {
fmt.Printf("Before %d %d\n", i, myTime.Unix())
c.L.Lock()
for !condition(myTime, timeSlice) {
c.Wait()
}
c.L.Unlock()
removeFromSlice(myTime, timeSlice)
c.Broadcast()
wg.Done()
fmt.Printf("After done %d\n", i)
}(i, now)
}
wg.Wait()
fmt.Println("Hello, playground")
}
我不认为这是做这种事情的正确方法它看起来很 hacky,有没有更好的方法?
-- 编辑 -- 在@Vorsprung 的回答之后,我认为在我的案例中最好的方法是制作一个 func 片段,它总是调用片段的第一个元素
package main
import (
"fmt"
"sync"
)
func makeFunc(id int) func() {
return func() {
fmt.Printf("called %d\n", id)
}
}
func main() {
var wg sync.WaitGroup
var funcSlice []func()
var m sync.Mutex
for i := 0; i < 5; i++ {
funcSlice = append(funcSlice, makeFunc(i))
wg.Add(1)
go func() {
defer wg.Done()
m.Lock()
defer m.Unlock()
funcSlice[0]()
funcSlice = funcSlice[1:]
}()
}
wg.Wait()
fmt.Println("finished")
}
给goroutines一个内部id,然后让它们按顺序互相调用。下面是如何工作的示例
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var c [5]chan int
for i := range c {
c[i] = make(chan int)
wg.Add(1)
go func(id int) {
defer wg.Done()
f := <-c[id]
fmt.Println("called from ", f, ". My id ", id)
if id < 4 {
fmt.Println(id+1, " next")
c[id+1] <- id
}
fmt.Println("ending ", id)
}(i)
}
c[0] <- 99
wg.Wait()
fmt.Println("bye")
}