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



posted @ 2022-03-09 04:14  咖喱给给啊  阅读(38)  评论(0)    收藏  举报