goroutine和chan
package main
import (
"errors"
"fmt"
"reflect"
"sync"
"syscall"
"unsafe"
)
var wg sync.WaitGroup
var once sync.Once
type Str struct {
num int
pid int
}
type hchan struct {
qcount uint // total data in the queue
dataqsiz uint // size of the circular queue
buf unsafe.Pointer // points to an array of dataqsiz elements
elemsize uint16
closed uint32
}
type ChanInfo struct {
Closed bool // 是否关闭
Len uint // channel内数据量
Cap uint // channel容量
Block bool // 是否已经阻塞
}
func ChanStatus(c interface{}) (*ChanInfo, error) {
v := reflect.ValueOf(c)
if v.Type().Kind() != reflect.Chan {
return nil, errors.New("type must be channel")
}
i := (*[2]uintptr)(unsafe.Pointer(&c))
h := (*hchan)(unsafe.Pointer(i[1]))
return &ChanInfo{
Cap: h.dataqsiz,
Len: h.qcount,
Closed: h.closed == 1,
Block: h.qcount >= h.dataqsiz,
}, nil
}
func GetCurrentThreadId() int {
var user32 *syscall.DLL
var GetCurrentThreadId *syscall.Proc
var err error
user32, err = syscall.LoadDLL("Kernel32.dll")
if err != nil {
fmt.Printf("syscall.LoadDLL fail: %v\n", err.Error())
return 0
}
GetCurrentThreadId, err = user32.FindProc("GetCurrentThreadId")
if err != nil {
fmt.Printf("user32.FindProc fail: %v\n", err.Error())
return 0
}
var pid uintptr
pid, _, err = GetCurrentThreadId.Call()
return int(pid)
}
func f1(ch1 chan int) {
defer wg.Done()
for i := 0; i < 98; i++ {
ch1 <- i
}
ch1 <- 666
ch1 <- 666
close(ch1)
}
func f2(ch1 chan int, ch2 chan Str) {
defer wg.Done()
for {
//ChanInfo, _ := ChanStatus(ch1)
x, ok := <-ch1
if x == 666 && ok == true {
break
}
var s Str
s.num = x
s.pid = GetCurrentThreadId()
//if ChanInfo.Closed
if ok == true {
ch2 <- s
}
}
}
func f3(ch1 chan int, ch2 chan Str) {
defer wg.Done()
for {
x, ok := <-ch1
if !ok {
break
}
var s Str
s.num = x
s.pid = GetCurrentThreadId()
ch2 <- s //可能是运行到这
}
// once.Do(func() { close(ch2) })
}
func main() {
ch1 := make(chan int, 100)
ch2 := make(chan Str, 100)
// ch3 := make(chan Str, 100)
wg.Add(3)
go f1(ch1)
go f2(ch1, ch2)
go f2(ch1, ch2)
wg.Wait()
close(ch2)
for {
x, ok := <-ch2
if !ok {
break
}
fmt.Println(x.num, x.pid)
}
}
如果直接用f3的这种方式 可能会造成这种情况发生 两个线程拿到一个索引,第一个拿到,第二个拿到就是空,直接退出,如果在内部关闭的话 就直接报错
0 107812
2 107812
3 107812
4 107812
5 107812
6 107812
7 107812
8 107812
9 107812
10 107812
11 107812
12 107812
13 107812
14 107812
15 107812
16 107812
17 107812
18 107812
19 107812
20 107812
21 107812
22 107812
23 107812
24 107812
25 107812
26 107812
27 107812
28 107812
29 107812
30 107812
31 107812
32 107812
33 107812
34 107812
35 107812
36 107812
37 107812
38 107812
39 107812
40 107812
41 107812
42 107812
43 107812
44 107812
45 107812
46 107812
47 107812
48 107812
49 107812
1 107104
浙公网安备 33010602011771号