下面是我的代码:
package main
import (
"sync/atomic"
"unsafe"
"sync"
"fmt"
"time"
)
const (
MAX_DATA_SIZE = 100
)
// lock free queue
type Queue struct {
head unsafe.Pointer
tail unsafe.Pointer
}
// one node in queue
type Node struct {
val interface{}
next unsafe.Pointer
}
// queue functions
func (self *Queue) enQueue(val interface{}) {
newValue := unsafe.Pointer(&Node{val: val, next: nil})
var tail,next unsafe.Pointer
for {
tail = self.tail
next = ((*Node)(tail)).next
if next != nil {
atomic.CompareAndSwapPointer(&(self.tail), tail, next)
}else if atomic.CompareAndSwapPointer(&((*Node)(tail).next), nil, newValue){
break
}
}
}
func (self *Queue) deQueue() (val interface{}, success bool){
var head,tail,next unsafe.Pointer
for {
head = self.head
tail = self.tail
next = ((*Node)(head)).next
if head == tail {
if next == nil {
return nil, false
}else {
atomic.CompareAndSwapPointer(&(self.tail), tail, next)
}
}else {
val = ((*Node)(next)).val
if atomic.CompareAndSwapPointer(&(self.head), head, next) {
return val, true
}
}
}
return
}
func main() {
var wg sync.WaitGroup
wg.Add(20)
queue := new(Queue)
queue.head = unsafe.Pointer(new(Node))
queue.tail = queue.head
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
t := time.Now()
queue.enQueue(t)
fmt.Println("enq = ", t)
}
}()
}
for i := 0; i < 10; i++ {
go func() {
ok := false
var val interface{}
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
val,ok = queue.deQueue()
for !ok {
val,ok = queue.deQueue()
}
fmt.Println("deq = ",val)
}
}()
}
wg.Wait()
}问题是,有时代码运行得很好,但有时它会失败,只是卡住了没有响应。
我的代码中有什么问题吗?
发布于 2012-09-07 02:23:11
下面是用@mkb建议的通道重写的上述代码(不包括无限队列大小)。
它锁不住了。
我建议你使用通道,除非你有很好的理由不这样做,因为Go团队已经花费了大量的精力来使它们可靠、高性能和易于使用。
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
const (
MAX_DATA_SIZE = 100
)
func main() {
runtime.GOMAXPROCS(4)
var wg sync.WaitGroup
wg.Add(20)
queue := make(chan time.Time, 10)
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
t := time.Now()
queue <- t
fmt.Println("enq = ", t)
}
}()
}
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
val := <-queue
fmt.Println("deq = ", val)
}
}()
}
wg.Wait()
}发布于 2013-01-21 21:52:25
在这段代码中有很多活跃的等待,我强烈建议像Nick的好代码一样干净地使用channel。
然而,这是我对原始问题“为什么被卡住了?”的确切答案:没有保证每个goroutine何时会让步,让其他goroutine执行,最有可能的是,当它在无限循环中时,它永远不会让步。
你可以通过在每个可能无限的for循环中使用runtime.Gosched()来解决这个问题:
产生处理器,允许其他goroutine运行。它不会挂起当前的goroutine,因此执行会自动恢复。
这个增强的代码运行速度几乎和原始代码一样快,但永远不会挂起:
package main
import (
"fmt"
"runtime"
"sync"
"sync/atomic"
"time"
"unsafe"
)
const (
MAX_DATA_SIZE = 100
)
// lock free queue
type Queue struct {
head unsafe.Pointer
tail unsafe.Pointer
}
// one node in queue
type Node struct {
val interface{}
next unsafe.Pointer
}
// queue functions
func (self *Queue) enQueue(val interface{}) {
newValue := unsafe.Pointer(&Node{val: val, next: nil})
var tail, next unsafe.Pointer
for {
tail = self.tail
next = ((*Node)(tail)).next
if next != nil {
atomic.CompareAndSwapPointer(&(self.tail), tail, next)
} else if atomic.CompareAndSwapPointer(&((*Node)(tail).next), nil, newValue) {
break
}
runtime.Gosched()
}
}
func (self *Queue) deQueue() (val interface{}, success bool) {
var head, tail, next unsafe.Pointer
for {
head = self.head
tail = self.tail
next = ((*Node)(head)).next
if head == tail {
if next == nil {
return nil, false
} else {
atomic.CompareAndSwapPointer(&(self.tail), tail, next)
}
} else {
val = ((*Node)(next)).val
if atomic.CompareAndSwapPointer(&(self.head), head, next) {
return val, true
}
}
runtime.Gosched()
}
return
}
func main() {
var wg sync.WaitGroup
wg.Add(20)
queue := new(Queue)
queue.head = unsafe.Pointer(new(Node))
queue.tail = queue.head
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
t := time.Now()
queue.enQueue(t)
fmt.Println("enq = ", t)
}
}()
}
for i := 0; i < 10; i++ {
go func() {
ok := false
var val interface{}
defer wg.Done()
for j := 0; j < MAX_DATA_SIZE; j++ {
val, ok = queue.deQueue()
for !ok {
val, ok = queue.deQueue()
runtime.Gosched()
}
fmt.Println("deq = ", val)
}
}()
}
wg.Wait()
}https://stackoverflow.com/questions/12291949
复制相似问题